<?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-3666775354459763953</id><updated>2011-11-24T08:24:18.563-07:00</updated><category term='PHP'/><category term='Python'/><category term='self help'/><category term='XMP'/><category term='Ruby'/><category term='Web Develoment'/><category term='CMS'/><category term='s/w opinions'/><category term='W3'/><category term='XML'/><category term='philosophy'/><category term='JSON'/><category term='musings'/><title type='text'>Expressed Opinions</title><subtitle type='html'>These are the opinions of the author - that is ...  me. I take full responsibility for whatever I say, as long as it doesn't cost me money.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>37</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-5070950606916931609</id><published>2011-05-18T18:08:00.003-06:00</published><updated>2011-05-18T18:12:02.791-06:00</updated><title type='text'>The Blog has Moved!!!</title><content type='html'>I've moved this blog to &lt;a href="http://mikehoward-musing.posterous.com/"&gt;http://mikehoward-musing.posterous.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Thanks for the fish&lt;br /&gt;&lt;br /&gt;Mike&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-5070950606916931609?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/5070950606916931609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=5070950606916931609' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/5070950606916931609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/5070950606916931609'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2011/05/blog-has-moved.html' title='The Blog has Moved!!!'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-8937108997576121322</id><published>2011-04-26T11:28:00.001-06:00</published><updated>2011-04-26T11:29:46.136-06:00</updated><title type='text'>Creating a Rails 3.0 Gem</title><content type='html'>&lt;h1 id="building_a_gem_for_rails_3"&gt;Building a Gem for Rails 3&lt;/h1&gt;&lt;b&gt;This is a 'work in progress' - any and all corrections, comments, suggestions&lt;/b&gt;&lt;br /&gt;&lt;b&gt;welcome!&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Believe it or not, it’s not that hard.&lt;br /&gt;&lt;br /&gt;Here’s the basic outline:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;lay out a basic Ruby gem, with the normal directory structure&lt;/li&gt;&lt;li&gt;decide how you need to hook into Rails&lt;br /&gt;&lt;ul&gt;&lt;li&gt;if you need to patch some of Rails internal structures - such as&lt;br /&gt;add some functionality to ActiveController - then you need to write&lt;br /&gt;a Railstie&lt;/li&gt;&lt;li&gt;if you need to add a controller, a model, view, rake task or a generator -&lt;br /&gt;then you probably should use an Engine. [the difference between a Railtie&lt;br /&gt;and an Engine is that an Engine is a Railtie with more stuff]&lt;/li&gt;&lt;li&gt;Or, if you want to embed an entire Application into another, you can use&lt;br /&gt;subclass Rails::Application. If you need to write an Application, then&lt;br /&gt;you need to find somebody who knows how to do it.&lt;/li&gt;&lt;li&gt;Or, if you want to make a Plugin, you should forget it and just build a gem&lt;br /&gt;and either implement a Railtie or an Engine&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;build, test as usual. Below I’ll show how you can hook your local, development&lt;br /&gt;gem into a locally run Rails app.&lt;/li&gt;&lt;li&gt;package and ship out to github.com and rubygems.org&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In everything which follows, I’m assuming that you are adding functionality to&lt;br /&gt;Rails which requires some sort of ‘initialization’.&lt;br /&gt;&lt;br /&gt;&lt;h2 id="what_does_8216requires_initialization8217_mean"&gt;What does ‘requires initialization’ mean?&lt;/h2&gt;&lt;br /&gt;Ok - when does your gem ‘require initialization’?&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;if you need to run a rake task or a generator to install some stuff in order for&lt;br /&gt;your gem to work - then it ‘requires initialization’. In fact, you should probably&lt;br /&gt;create an Engine.&lt;/li&gt;&lt;li&gt;if you’re adding controllers, views, etc, then you need an Engine&lt;/li&gt;&lt;li&gt;if you want to monkey patch ActiveController or one of the other basic Rails&lt;br /&gt;classes, then you will want to ‘include MyGemModule’ into that Rails class when&lt;br /&gt;it is autoloaded. For that you need to insert yourself into the autoload sequence&lt;br /&gt;and so you ‘require initialization’. Specifically, you need at least a Railtie.&lt;/li&gt;&lt;li&gt;finally, if you’re not doing any of this and there is some way for your gem&lt;br /&gt;to provide services without any startup initialization and &lt;em&gt;without living in any&lt;br /&gt;namespace Rails knows about&lt;/em&gt;, then you &lt;em&gt;don’t&lt;/em&gt; need initialization.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;So, the answer is - pretty much all gems which will extend Rails are going to&lt;br /&gt;‘require initialization’ and your initialization stuff goes into your Railtie&lt;br /&gt;or Engine.&lt;br /&gt;&lt;br /&gt;So …&lt;br /&gt;&lt;br /&gt;&lt;h2 id="what_goes_into_your_railtie_engine"&gt;What goes into your Railtie / Engine&lt;/h2&gt;&lt;br /&gt;Surprisingly little - but figuring out what that ‘little’ is can be&lt;br /&gt;daunting.&lt;br /&gt;&lt;br /&gt;Here’s the Railtie I wrote for my &lt;code&gt;manage_meta&lt;/code&gt; gem:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;module ManageMeta&lt;br /&gt;  class Railtie &amp;lt; Rails::Railtie&lt;br /&gt;    initializer "application_controller.initialize_manage_meta" do&lt;br /&gt;      ActiveSupport.on_load(:action_controller) do&lt;br /&gt;        include ManageMeta&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;There’s a lot going on here in 9 lines (typical Ruby compactness!)&lt;br /&gt;&lt;br /&gt;Before going into this code, it will help to put it in the context of how&lt;br /&gt;this gem is structured.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;the gem and github repository are both named &lt;em&gt;manage_meta&lt;/em&gt;&lt;/li&gt;&lt;li&gt;all the code which &lt;em&gt;does something&lt;/em&gt; is in &lt;code&gt;manage_meta/lib&lt;/code&gt;&lt;/li&gt;&lt;li&gt;the file which is required is named &lt;code&gt;manage_meta/lib/manage_meta.rb&lt;/code&gt;. All it does&lt;br /&gt;is &lt;code&gt;require&lt;/code&gt; files from &lt;code&gt;manage_meta/lib/manage_meta/&lt;/code&gt;.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It always requires &lt;code&gt;manage_meta/lib/manage_meta/manage_meta.rb&lt;/code&gt;: this allows&lt;br /&gt;me to write unit tests which are independent of Rails&lt;/li&gt;&lt;li&gt;It conditionally &lt;code&gt;require&lt;/code&gt;s the Railtie.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Here it is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;require 'manage_meta/manage_meta'&lt;br /&gt;require 'manage_meta/railtie' if defined? Rails&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;OK - so all we need to do is get our Rails app to include &lt;code&gt;manage_meta/lib/manage_meta.rb&lt;/code&gt;.&lt;br /&gt;But this is a distraction right now. We’ll get back to it when we go&lt;br /&gt;over the Rails boot process.&lt;br /&gt;&lt;br /&gt;By the way, &lt;strong&gt;the names are significant!&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The root directory &lt;code&gt;manage_meta&lt;/code&gt;, the top-level require file &lt;code&gt;manage_meta/lib/manage_meta.rb&lt;/code&gt;,&lt;br /&gt;and the subdirectory of lib &lt;code&gt;manage_meta/lib/manage_meta/&lt;/code&gt; need to &lt;em&gt;all&lt;/em&gt; be&lt;br /&gt;the gem name.&lt;/li&gt;&lt;li&gt;I &lt;em&gt;think&lt;/em&gt; that the Railtie (or Engine) really needs to be named &lt;code&gt;railtie.rb&lt;/code&gt;&lt;br /&gt;(or &lt;code&gt;engine.rb&lt;/code&gt;) in order for Rails to find it. [this is a guess which I may&lt;br /&gt;never resolve because: 1. it works when I do it like this and 2. there’s no reason&lt;br /&gt;not to. If anybody can confirm this, I’ll remove this caveat and give them credit]&lt;/li&gt;&lt;li&gt;module ManageMeta - I’m extending my module with some Rails specific code.&lt;br /&gt;While not visible here, this is conditionally included in &lt;code&gt;lib/manage_meta.rb&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;OK, back to the Railtie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;module ManageMeta&lt;br /&gt;&lt;br /&gt;Your gem must be namespaced to a Module and you have to define your Railtie (or Engine)&lt;br /&gt;within that module.&lt;/li&gt;&lt;li&gt;class Railtie &amp;lt; Rails::Railtie (or class Engine &amp;lt; Rails::Engine)&lt;br /&gt;&lt;br /&gt;Sure, you can call it Bob if you want, but why bother? It’s real name is&lt;br /&gt;ManageMeta::Railtie or MyGem::Railtie - which is safely namespaced, so there&lt;br /&gt;won’t be any conflict here.&lt;br /&gt;&lt;br /&gt;The important thing is that this get’s you all the stuff in Railtie - most importantly,&lt;br /&gt;for what we’re talking about here, this is where you get the ability to &lt;em&gt;initialize&lt;/em&gt;&lt;br /&gt;by calling &lt;code&gt;initializer&lt;/code&gt; [defined in &lt;code&gt;rails/lib/rails/inializable.rb&lt;/code&gt; (see the pattern?&lt;br /&gt;&lt;em&gt;everything is a gem&lt;/em&gt;)]&lt;/li&gt;&lt;li&gt;initializer “application&lt;em&gt;controller.initialize&lt;/em&gt;manage_meta” do …&lt;br /&gt;&lt;br /&gt;&lt;code&gt;initializer&lt;/code&gt; takes a &lt;em&gt;name&lt;/em&gt;, a block, and (optionally) a couple of options. The&lt;br /&gt;&lt;em&gt;option&lt;/em&gt; keys are &lt;code&gt;:before&lt;/code&gt; and &lt;code&gt;:after&lt;/code&gt; and we’re going to ignore them for now.&lt;br /&gt;&lt;br /&gt;It builds an &lt;code&gt;Initializer&lt;/code&gt; instance and stuffs it into the array-like object named&lt;br /&gt;&lt;code&gt;initializers&lt;/code&gt;. I say it’s array-like because all the Initializer instances are&lt;br /&gt;in sequence, but the options allow anyone &lt;em&gt;in the know&lt;/em&gt; to place their specific&lt;br /&gt;Initializer.&lt;br /&gt;&lt;br /&gt;Let’s just take it on faith that as Rails boots, it goes through &lt;code&gt;initializers&lt;/code&gt;&lt;br /&gt;and runs the code blocks we pass in.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Here’s the &lt;a href="" id="initializer"&gt;&lt;code&gt;initializer&lt;/code&gt;&lt;/a&gt; code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;def initializer(name, opts = {}, &amp;amp;blk)&lt;br /&gt;  raise ArgumentError, "A block must be passed when defining an initializer" unless blk&lt;br /&gt;  opts[:after] ||= initializers.last.name unless initializers.empty? || initializers.find { |i| i.name == opts[:before] }&lt;br /&gt;  initializers &amp;lt;&amp;lt; Initializer.new(name, nil, opts, &amp;amp;blk)&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ActiveSuport.on&lt;em&gt;load(:action&lt;/em&gt;controller) do ; include ManageMeta ; end&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Finally&lt;/strong&gt; we get to the place we were going.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;ActiveSupport&lt;/code&gt; seems to be pretty much a support library which just lays around like&lt;br /&gt;a sleeping dog until you poke it to do something. Then it does it and goes back to&lt;br /&gt;sleep.&lt;br /&gt;&lt;br /&gt;One of the things &lt;code&gt;ActiveSupport&lt;/code&gt; provides is support for creating queues of code&lt;br /&gt;blocks which can be ‘run later’. This support is defined in&lt;br /&gt;&lt;code&gt;active_support/lib/active_support/lazy_load_hooks.rb&lt;/code&gt; - which defines 3 class&lt;br /&gt;methods:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;on_load(name, options, &amp;amp;block) - which is we use to add our code to a hook&lt;/li&gt;&lt;li&gt;run&lt;em&gt;load&lt;/em&gt;hooks(name, base = Object) - which runs all the defined hooks. We don’t&lt;br /&gt;touch this - but it’s really important.&lt;/li&gt;&lt;li&gt;execute_hook(base, options, block) - which we never touch - it’s used by&lt;br /&gt;&lt;code&gt;run_load_hooks&lt;/code&gt; to actually run the code block on the object&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;So, here’s the short version of what those 9 lines do:&lt;br /&gt;&lt;br /&gt;It adds the statement &lt;code&gt;include ManageMeta&lt;/code&gt; to the autoload sequence which is triggered&lt;br /&gt;when ActionController is first loaded.&lt;br /&gt;&lt;br /&gt;It does it by adding that code to the &lt;code&gt;on_load&lt;/code&gt; chain keyed to the name &lt;code&gt;:action_controller&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h2 id="let8217s_try_to_generalize_this"&gt;Let’s Try to Generalize This&lt;/h2&gt;&lt;br /&gt;OK - so how did I know how to do this?&lt;br /&gt;&lt;br /&gt;Code crawling - of course.&lt;br /&gt;&lt;br /&gt;I grep’ed the Rails 3.0.6 gems for calls to &lt;code&gt;run_load_hooks&lt;/code&gt; and found the following&lt;br /&gt;keys defined:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;:action_mailer&lt;br /&gt;:action_controller&lt;br /&gt;:action_view&lt;br /&gt;:active_record&lt;br /&gt;&lt;br /&gt;:i18n&lt;br /&gt;:before_initialize&lt;br /&gt;:before_eager_load&lt;br /&gt;:after_initialize&lt;br /&gt;:before_configuration&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The first four (&lt;code&gt;action_mailer&lt;/code&gt;, &lt;code&gt;action_controller&lt;/code&gt;, &lt;code&gt;action_view&lt;/code&gt;, and &lt;code&gt;active_record&lt;/code&gt;)&lt;br /&gt;all call &lt;code&gt;run_load_hooks&lt;/code&gt; at the end of &lt;class-name&gt;::Base. So if you want or need&lt;br /&gt;to hack these base classes, you just copy the code above and use the appropriate&lt;br /&gt;&lt;code&gt;name&lt;/code&gt;.&lt;/class-name&gt;&lt;br /&gt;&lt;br /&gt;So far I haven’t found a need to hook into any of the other 5, so I’ll just leave&lt;br /&gt;those &lt;em&gt;as an exercise for the reader&lt;/em&gt;. [send me a link to what you find and I’ll&lt;br /&gt;add it here]&lt;br /&gt;&lt;br /&gt;&lt;h2 id="but_but_but_8230_what_about_engines"&gt;But but but … What about Engines?&lt;/h2&gt;&lt;br /&gt;Well, one place you need an &lt;code&gt;Engine&lt;/code&gt; if you have some stuff in the &lt;code&gt;app&lt;/code&gt; directory.&lt;br /&gt;&lt;br /&gt;So what you do is add an &lt;code&gt;app&lt;/code&gt; directory to your gem, structure it like a Rails&lt;br /&gt;&lt;code&gt;app&lt;/code&gt; directory - and it “just works”.&lt;br /&gt;&lt;br /&gt;Another place is if you want some rake tasks.&lt;br /&gt;&lt;br /&gt;What you do then is create a directory called &lt;code&gt;manage_meta/lib/tasks/&lt;/code&gt; and put&lt;br /&gt;your rake tasks in files called &lt;code&gt;a_task.rake&lt;/code&gt; - and it “just works” too.&lt;br /&gt;&lt;br /&gt;Another place is when you need a generator.&lt;br /&gt;&lt;br /&gt;Here you need to call the &lt;code&gt;generate&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I haven’t messed with building a generator yet - but it’s on the list.&lt;br /&gt;&lt;br /&gt;As soon as I get to it (and have at least a less vague idea of what to do), I’ll&lt;br /&gt;add some stuff &lt;strong&gt;here&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 id="but_8230_but_8230_but_8230_how_does_rails_find_my_gem_and_all_this_goodness"&gt;But … But … But … How does Rails Find my Gem and All this Goodness?&lt;/h2&gt;&lt;br /&gt;Glad you asked.&lt;br /&gt;&lt;br /&gt;The answer is “The &lt;strong&gt;bundler&lt;/strong&gt; did it!”&lt;br /&gt;&lt;br /&gt;If you look in your Rails app in &lt;code&gt;config/boot.rb&lt;/code&gt;, you will find a file which&lt;br /&gt;contains something like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;require 'rubygems'&lt;br /&gt;&lt;br /&gt;# Set up gems listed in the Gemfile.&lt;br /&gt;ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)&lt;br /&gt;&lt;br /&gt;require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Here’s an easy way to see what this does.&lt;br /&gt;&lt;br /&gt;This is my Ruby environment in the top directory of a Rails site I’m working&lt;br /&gt;on. [I’m using rvm, so it shows the ruby and stuff I have set up for this site]&lt;br /&gt;This is just simply running &lt;code&gt;irb&lt;/code&gt;, so the bundler setup stuff isn’t run.&lt;br /&gt;&lt;br /&gt;Here’s the default $LOAD_PATH&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;mike:clovetech2 mike$ irb&lt;br /&gt;ruby-1.9.2-p180 :001 &amp;gt; puts $:.join "\n"&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/site_ruby/1.9.1&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/site_ruby/1.9.1/x86_64-darwin10.7.3&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/site_ruby&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/vendor_ruby/1.9.1&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/vendor_ruby/1.9.1/x86_64-darwin10.7.3&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/vendor_ruby&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/x86_64-darwin10.7.3&lt;br /&gt; =&amp;gt; nil&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Here’s what $LOAD_PATH looks like after &lt;code&gt;bundler/setup&lt;/code&gt; is &lt;code&gt;require&lt;/code&gt;d. All those&lt;br /&gt;extra files are pulled in from the Gemfile.&lt;br /&gt;&lt;br /&gt;Most of the new stuff are gems which I’ve pulled from &lt;code&gt;rubygems.org&lt;/code&gt; and which&lt;br /&gt;are stuffed &lt;code&gt;rvm&lt;/code&gt;’s gemset for the Ruby I’m using. It also adds in my development&lt;br /&gt;gems. More below&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;mike:clovetech2 mike$ rails c&lt;br /&gt;Loading development environment (Rails 3.0.6)&lt;br /&gt;ruby-1.9.2-p180 :001 &amp;gt; puts $:.join "\n"&lt;br /&gt;/Users/mike/Rails/clovetech2/lib&lt;br /&gt;/Users/mike/Rails/clovetech2/vendor&lt;br /&gt;/Users/mike/Rails/clovetech2/app/controllers&lt;br /&gt;/Users/mike/Rails/clovetech2/app/helpers&lt;br /&gt;/Users/mike/Rails/clovetech2/app/mailers&lt;br /&gt;/Users/mike/Rails/clovetech2/app/models&lt;br /&gt;/Users/mike/Rails/Mikes-Gems/use_tinymce/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/webrat-0.7.3/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/sqlite3-ruby-1.3.3/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/sqlite3-1.3.3/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/rails-3.0.6/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/railties-3.0.6/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/thor-0.14.6/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/nokogiri-1.4.4/lib&lt;br /&gt;/Users/mike/Rails/Mikes-Gems/manage_meta/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/database_cleaner-0.6.6/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/autotest-rails-4.1.0/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/annotate-models-1.0.4/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/activeresource-3.0.6/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/activerecord-3.0.6/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/arel-2.0.9/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/actionmailer-3.0.6/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/mail-2.2.15/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/treetop-1.4.9/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/polyglot-0.3.1/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/mime-types-1.16/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/actionpack-3.0.6/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/tzinfo-0.3.26/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/rack-test-0.5.7/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/rack-mount-0.6.14/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/rack-1.2.2/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/erubis-2.6.6/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/activemodel-3.0.6/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/i18n-0.5.0/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/builder-2.1.2/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/activesupport-3.0.6/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/abstract-1.0.0/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/ZenTest-4.5.0/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@global/gems/rake-0.8.7/lib&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/bundler-1.0.10/lib&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/site_ruby/1.9.1&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/site_ruby/1.9.1/x86_64-darwin10.7.3&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/site_ruby&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/vendor_ruby/1.9.1&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/vendor_ruby/1.9.1/x86_64-darwin10.7.3&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/vendor_ruby&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1&lt;br /&gt;/Users/mike/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/x86_64-darwin10.7.3&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/actionpack-3.0.6/lib/action_controller/vendor/html-scanner&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/rack-mount-0.6.14/lib/rack/mount/vendor/multimap&lt;br /&gt;/Users/mike/.rvm/gems/ruby-1.9.2-p180@clovetech2/gems/rack-mount-0.6.14/lib/rack/mount/vendor/regin&lt;br /&gt; =&amp;gt; nil&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Take a look at &lt;code&gt;/Users/mike/Rails/Mikes-Gems/use_tinymce/lib&lt;/code&gt;&lt;br /&gt;and &lt;code&gt;/Users/mike/Rails/Mikes-Gems/manage_meta/lib&lt;/code&gt;. Those are my development&lt;br /&gt;gems.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;bundler&lt;/strong&gt; has hooked my development gems into the load path.&lt;br /&gt;I pulled that off by specifying those gems using:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;`gem "manage_meta", :path =&amp;gt; "~/Rails/Mikes-Gems/manage_meta"`&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Take a look at the &lt;a href="http://gembundler.com/"&gt;&lt;strong&gt;bundler&lt;/strong&gt; site’s&lt;/a&gt;&lt;br /&gt;for a discussion of the &lt;a href="http://gembundler.com/gemfile.html"&gt;Gemfile&lt;/a&gt;&lt;br /&gt;options.&lt;br /&gt;&lt;br /&gt;&lt;h3 id="and_wait_8230_there8217s_more"&gt;And Wait … There’s More&lt;/h3&gt;&lt;br /&gt;Notice that only the &lt;code&gt;lib&lt;/code&gt; directories for each included gem are added to&lt;br /&gt;the $LOAD_PATH.&lt;br /&gt;&lt;br /&gt;So how does the Engine get to the &lt;code&gt;app&lt;/code&gt; directory and how does &lt;code&gt;rake&lt;/code&gt; find&lt;br /&gt;rake tasks?&lt;br /&gt;&lt;br /&gt;The answer - as usual - is &lt;em&gt;convention&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;Directory structure is important. &lt;code&gt;app&lt;/code&gt; has to be locatable in a standard way&lt;br /&gt;using &lt;code&gt;File.expand_path&lt;/code&gt;.  For example, I strongly suspect that Rails::Engine&lt;br /&gt;contains something which effectively does:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;$LOAD_PATH &amp;lt;&amp;lt; File.expand_path('../../../app', __FILE__)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;(it doesn’t look like this - Rails is far more generic and self-programming than&lt;br /&gt;something this straightforward)&lt;br /&gt;&lt;br /&gt;Anyway - the thing to realize is that - for mere mortals - it’s best to stick&lt;br /&gt;to the “correct” directory structure and naming conventions.&lt;br /&gt;&lt;br /&gt;So if you build it and it doesn’t work - check your names and directory structure.&lt;br /&gt;&lt;br /&gt;&lt;h2 id="a_little_about_initializers"&gt;A Little about Initializers&lt;/h2&gt;&lt;br /&gt;&lt;code&gt;railties/lib/rails/initializable.rb&lt;/code&gt; defines two classes, some class methods,&lt;br /&gt;and an instance method:&lt;br /&gt;&lt;br /&gt;The classes are:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Initializer - which is a named container for a block of code. It has provision&lt;br /&gt;for a &lt;code&gt;context&lt;/code&gt; [which turns out to be a binding in which to run the code block]&lt;br /&gt;and &lt;code&gt;before&lt;/code&gt; and &lt;code&gt;after&lt;/code&gt; properties which are used to provide a sorting order.&lt;br /&gt;(more below)&lt;/li&gt;&lt;li&gt;Collection &amp;lt; Array - which is an array which can be sorted using the &lt;code&gt;tsort&lt;/code&gt;&lt;br /&gt;method in the standard Ruby library. Sorting uses the &lt;code&gt;before&lt;/code&gt; and &lt;code&gt;after&lt;/code&gt;&lt;br /&gt;properties.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The class methods are:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;initializers&lt;/code&gt; - which is a Collection&lt;/li&gt;&lt;li&gt;&lt;code&gt;initializers_chain&lt;/code&gt; - which constructs an &lt;code&gt;initializers&lt;/code&gt; instance for the class&lt;br /&gt;which calls it. Specifically, it consists of all &lt;code&gt;ancestor&lt;/code&gt; classes and modules&lt;br /&gt;which &lt;code&gt;respond_to?&lt;/code&gt; &lt;code&gt;initializer&lt;/code&gt; [in reverse order, so the the initializations&lt;br /&gt;are processed from the top of the class/module hierarchy down to the lowest&lt;br /&gt;descendent (which is &lt;em&gt;self&lt;/em&gt;)]&lt;/li&gt;&lt;li&gt;&lt;code&gt;initializers_for(binding)&lt;/code&gt; - returns an initializers chain where each&lt;br /&gt;Initializer instance is bound to &lt;em&gt;binding&lt;/em&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;initializer(name, opts = {}, &amp;amp;blk)&lt;/code&gt; - whom we’ve seen before up &lt;a href="http://www.blogger.com/post-edit.g?blogID=3666775354459763953&amp;amp;postID=8937108997576121322#initializer"&gt;here&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;The instance method is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;initializers&lt;/code&gt; - constructs and caches the &lt;code&gt;initializer_chain&lt;/code&gt; constructed for this&lt;br /&gt;instance of the class which mixes in Rails::Initializable.&lt;/li&gt;&lt;/ul&gt;All in all it’s really clever, remarkably flexible and hellish to unravel.&lt;br /&gt;&lt;br /&gt;But, once you know it’s there and how to find the keys you need, it makes a lot of&lt;br /&gt;sense and is clearly very efficient, flexible, and powerful&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-8937108997576121322?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/8937108997576121322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=8937108997576121322' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8937108997576121322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8937108997576121322'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2011/04/creating-rails-30-gem.html' title='Creating a Rails 3.0 Gem'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-7457044116049032115</id><published>2010-12-25T08:34:00.007-07:00</published><updated>2010-12-26T08:40:50.330-07:00</updated><title type='text'>Infinite Recursion in Parser Generators</title><content type='html'>Well, I've stuck my foot in it again and doing something which doesn't make a lot of sense.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Skipping the details, I decided I need to write a parser in PHP and the language I'm designing is embedded in PHP - which has a complex syntax and . . . anyway, one thing led to another and I've ended up writing kind of a parser generator in PHP.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's not really a parser generator - it's more like a programmable parser where the program is a grammar specification.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, I broke out the Dragon book and started reading, built a programmable recursive descent parser framework object and a hand coded parser for language grammars so I can can program it and a programmable lexical scanner  - all in PHP and it all works pretty well.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And then . . .&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I couldn't solve my problem with it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why, you ask?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Well,  the problem I have  cannot be solved by a parse tree created from a right-recursive grammar - which is what the book says a recursive descent parser needs to process.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Because when a recursive descent parser hits a left recursive production (which is what I need for my problem) it goes into an infinitely deep recursion.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why does it do that?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's stupid.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It turns out that no only will simple productions like: &lt;i&gt;a : a TERMINAL ;&lt;/i&gt; create infinite recursions, but various, well hidden, mutual recursions will as well.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So - having faith in the Book - I decided maybe I need something which handles left recursive grammars. So I read and read and thought and thought and - as usually happens - I got tired, went to bed, and woke up this morning with a realization:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;"It's not the recursion &lt;i&gt;dummy&lt;/i&gt;, it's because processing non-terminals don't eat tokens!!!!!"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If that doesn't mean much to you - that's OK. The rest of this post is a boring explanation of what's happening and how to fix it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First of all - why isn't it obvious from the book? Because it's not in there because:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;The book defines a mathematical formalism to describe language structure and parsing&lt;/li&gt;&lt;li&gt;Like good mathematicians, they then ignore the actual problem and get buried in the formalism. And then . . .&lt;/li&gt;&lt;li&gt;They come up with ways to solve problems in the formalism using programming techniques and computer constraints available at the time they are working&lt;/li&gt;&lt;li&gt;The 2nd, 3rd, etc generation of 'students' become teachers and so they just teach the formalism &lt;i&gt;in the computing context of the time of the original work&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;My dragon book is copyright 1977. &lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Torben Ægidius Mogensen's "Basics of Compiler Design" is copyright 2000 through 2010 [nicely written, by the way] and the syntax analysis is a rehash of the stuff in the Dragon book [to be fair, I didn't read it all, but this is true to the margin of error inherent with a quick skim]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Believe it or not, things have changed.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;The Apple 2 computer didn't exist in 1977 (I don't think it did. I got mine in 1979 or 1980) and it maxed out a a whopping 64 Kilobytes of RAM [that's 1024 bytes]. The processor executed one instruction about every couple of microseconds. In other words, both memory and speed were very very limited, so a lot of work went into algorithm design - at the expense of clarity and simplicity of code.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;As a result, the compiler generators tend to avoid recursion ["function calls are expensive and take a lot of RAM"], but rather tended towards memory and speed efficient algorithms. As a result, the compiler generator section of the Dragon book is heavy into table driven parsers using conventional, non-recursive, non-functional programming techniques.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;And - finally getting to the point - they are so deep into formalism and computing environment, they never actually get to the point of "what causes infinite recursion in parsers".&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Well, here's the answer: any algorithm which revisits the same non-terminal without consuming a terminal symbol will infinitely recurse.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Huh?&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;This highlights another problem in understanding compiler generation: the compiler-eze terminology stinks. It emphasizes the &lt;i&gt;algorithms&lt;/i&gt;, not the problem we're trying to solve.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;So, here's what the Parsing Problem is:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;blockquote&gt;Given a string of characters, does it make sense in a specific, grammatical language?&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;OK - that's not specific enough to answer. So let's make it more concrete:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;First we will define a bunch of things we will call words and symbols. A word will be a string of 'letters' without any spaces in them. In English we also allow hyphens, so 'cat-food' could be classified as a word. In PHP a word might be a reserved word - 'foreach' or 'if' - or something like that. Anyway, we decide  how to find these things in a string of characters.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;We're going to call the things we find 'tokens' and it's the job of the 'lexical analyzer' to eat the string of characters and spit out an ordered list of 'tokens'.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;These tokens are what the Language Grammarians call 'terminals' or 'terminal symbols'.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;I'd rather call them 'tokens' or 'words' because that puts the focus back on &lt;i&gt;what they are in the language&lt;/i&gt;. The term 'terminal' puts the focus on the activity of the parser - which we haven't gotten to yet.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Now, you might try to build a grammar description using only 'tokens', but it would get pretty large pretty fast and it would be really limited.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;So you need something else. You need things which represent &lt;i&gt;parts&lt;/i&gt; of the language. For example, you might need something called a 'sentence' [starts with a capitalized word and ends in a terminating punctuation mark: . or ! or ?] and maybe a 'paragraph' and maybe . . . well you get the idea.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;These things which represent parts of the language can be composed of tokens or other parts of languages. In fact, in order to be really useful, these parts need to be able to refer to themselves as part of their definition - that is 'be recursively defined'.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;For example, lets say I have only four words: A, B, C, and D. I also have a couple of symbols, say AND and OR. That's my whole vocabulary.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Now let's say I want to construct sentences. I might say something like:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sentence : A AND B | A OR B | C | D ;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;where I'm using ':' to mean 'defined as' and '|' as 'or it might be' and ';' for 'that's all folks'.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;But this is kind of limiting. So let's say I want to build more sentences than I can list using only words and symbols.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;word : A | B | C | D;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sentence : sentence AND sentence | sentence OR sentence | word ;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;In compiler-eze, these parts of sentences are called 'non-terminals' - again, putting the emphasis on the process of parsing [the parser can't stop on a non-terminal] rather than on the structure of the language. I'm going to call them 'fragments'.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;Now, there are two ways I can use a grammar:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;I can build sentences using it - which you do all the time: writing, speaking, creating programs, etc.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;I can transform strings of characters (or sounds) into sentences so I can understand them - this is called 'parsing'&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Before we get to parsing, let's look at how we can use the grammar to create a sentence.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Let's say I want to build a sentence - but I really don't care what it means, only that's it's grammatically correct.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;I'll start with the fragment &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sentence.&lt;/span&gt; But this doesn't get me a string of characters. Grammars can only build sequences of 'fragments' and 'tokens'. Tokens are made up of sequences of characters - which is what I want - but 'fragments' aren't: they are made up of 'fragments' and 'tokens'. &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;So, in order to build a character string - or say something in the language - I have to get rid of all the 'fragments' so that I have a string of 'tokens' which I can (at least theoretically) feed to the un-lexical un-scanner which will produce a string of characters - which I can then print in a book.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;So how do I proceed? (the arrow (-&gt;) means 'replace a 'fragment' on the left with  one of the alternatives of the right side of the definition of the 'fragment' in the sequence and write it on the right side of the arrow.) (which is easier to do than say)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sentence -&gt; sentence AND sentence -&gt; A AND sentence -&gt; A AND D&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;and now I'm done. I have 'produced' a sequence of 'tokens' [TERMINALS in compiler-eze]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;which I can un-lexical analyze to produce a sequence of characters.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Now in compiler-eze, the alternatives on the right side of the definition of 'sentence' are called 'productions', because replacing a 'fragment' by one of them 'produces' something which is grammatically correct.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Ok - this is pretty straight forward, if boring. &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style=";font-family:georgia;font-size:medium;"  &gt;So let's turn to the 'parsing'. That is, given a string of characters, is it a grammatically correct sentence?&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=";font-family:georgia;font-size:medium;"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=";font-family:georgia;font-size:medium;"  &gt;The mathematicians would say 'it's grammatically correct if (and only if) there is a sequence of replacement operations I can find using productions which will generate the sentence'. So - as they would have it - they have 'reduced' the problem of 'parsing' to finding a sequence of productions which will produce the sentence.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;How do we do that? The Dragon book starts by analyzing algorithms, but let's take a different approach: let's look at what we do when 'parsing' a sentence somebody says or that we've just read.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;What I think you do (or we do) is look over the sentence and divide it up into chunks which make some sort of sense. Like 'Joe ran through the forrest'. Well, what's this about? 'Joe'&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;What did he do? 'ran' Where did he do it? 'through the forrest'. Stuff like that.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Let's formalize this procedure:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;First we'll lexically analyze the sentence: for 'Joe ...' this amounts to classifying each word according to its possible uses:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;'Joe' - is a noun and a name. It can be used in a subject or the object of a phrase&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;'ran' - is a verb. It can be used as a 'verb', as part of a predicate, part of a compound verb, or a phase ['seen to run']&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;etc&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Then we start parsing by examining the first token: Joe. Some sentences start with a noun, so we put 'Joe' on the shelf and look at the next word to see if it fits with how sentences which start with nouns are constructed. etc.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;The point is, we are scanning from left to right and trying sentence forms to see if they fit&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;the noise we just heard or read. [left to right, right to left, up to down - doesn't matter so much as the fact that it's really focusing on one word at a time in a consistent order].&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;So, in parsing we have &lt;i&gt;two&lt;/i&gt; scans going on:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;we are scanning the token stream&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;we are also scanning across a production to see if these tokens fit into it&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;The 'parse' terminates when the token stream is exhausted and all the tokens have been stuffed into 'fragments' OR something won't fit into any fragment. This is controlled by the sequence of scans across productions. Each time we start scanning, we start with some 'fragment' definition and exhaustively try all of it's productions to find a fit with the token stream - remember that we are scanning the stream left to right. So the only way to get into an infinite recursion is to find a production scan which does not terminate.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Scanning a production terminates on one of three ways:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;a segment of the token stream matches the entire production - then the production is accepted. Accepting means that we don't have to look at those tokens any more and we can make a record of the fragment we recognized.&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style=";font-family:georgia;font-size:medium;"  &gt; [in compiler-eze we then 'reduce' by replacing the production by it's non-terminal in the non-terminal definition (again, emphasis on algorithm rather than process]&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style=";font-family:georgia;font-size:medium;"  &gt;a token doesn't fit, in which case the production is rejected.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style=";font-family:georgia;font-size:medium;"  &gt;the production can be empty - and so it's trivially satisfied. [I forgot this early and have to think some more about it. Golly! that's meat for another post on this topic]&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;So if - in our scan across the production - we never look at any 'tokens', we will never terminate the scan. How can this happen?&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Here's an artificial example:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;frag1 : frag2 | WORD1 ;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;frag2 : frag1 | WORD2 ;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;No matter what I scan, my production scan will first look for &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;frag2&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt; which will look for &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;frag1&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt; which will look for &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;frag2&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt; which will . . . and I will &lt;i&gt;never&lt;/i&gt; examine a token, so I will never reach the end of the token stream.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;To go to a less artificial example,&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style=";font-family:georgia;font-size:medium;"  &gt; let's go back to my A, B, C, D language.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;I'm given with a sentence A AND C and I want to see if it can be produced by the grammar. I decide to 'run the grammar backward' to see if I can find a sequence of substitutions which work.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;OK, I start by guessing it's a 'sentence', so I write down:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sentence&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Now I say - 'what production might this be? Let's try the first one!', so I grab:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sentence AND sentence&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;Now you can look at the whole sentence and say 'Yep!!! It fits', but the computer will only look at what it's programmed to do. So, lets say that I've programmed up a recursive descent parser, which works by defining a function for each 'fragment' which it calls when it sees it's name in a production.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;So my 'parser' will see &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;'sentence'&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt; and call the 'sentence' function which will then look at the first production and will see &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sentence&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt; and will call the 'sentence' function and . . .&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;And there you are - infinite recursion.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;So we can't use a recursive descent parer. Right? Well, . . .&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;The recursion isn't caused by the parsing method, it's caused by any algorithm which attempts to match the same 'fragment' twice without recognizing and moving past a 'token'. &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;So infinite recursion in parsing results from designing an algorithm (any algorithm) which can cycle through a sequence of 'fragments' without ever recognizing (and using) a 'token'.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;So, can I patch up a 'recursive descent parser' so that it handles 'right recursion' and other forms of infinite recursion?&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Sure. I just have to keep track of my progress through the token stream and reject any production in which a 'fragment' occurs which I'm in the (recursive) process of examining AND which is at the same place in the token stream as it was before. Again, this will be easier to code than to write.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;I'll post a note when I've finished fixing this thing - in case you want to look at the code&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Mike&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&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/3666775354459763953-7457044116049032115?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/7457044116049032115/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=7457044116049032115' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7457044116049032115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7457044116049032115'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2010/12/infinite-recursion-in-parser-generators.html' title='Infinite Recursion in Parser Generators'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-4587166654603842392</id><published>2010-08-02T06:41:00.005-06:00</published><updated>2010-08-02T08:40:37.733-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='musings'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='self help'/><title type='text'>Change - again</title><content type='html'>Just about everyone I know would rather die than change something they believe.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's too vague.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let's say I believe I'm too fat. That can make sense if I look in the mirror and see somebody who looks like a sphere. But for an anorexic, when they look in the mirror they see somebody who looks like a stick.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The reason we say they are 'anorexic' isn't because they look like a stick. It's because they look like a stick and think that they are too fat AND they won't change what they believe.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So how do we react to this?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We call something like this a 'disease' and look for something to &lt;i&gt;do&lt;/i&gt; to them to &lt;i&gt;make&lt;/i&gt; them change. Probably some chemical we can put in a pill or an injection or a patch or a suppository.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Does it really make sense that an inert chemical can cause someone to have a specific idea? Isn't an 'idea' or a 'belief' more complex and specific than a single chemical?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what can these 'drugs' really do? - other than slow down or speed up thinking?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If that's all they can do, then 'drugging' people just changes their ability to think - their 'thinking environment' - not their beliefs.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So 'drugs' can't 'cure their disease', although they may make it possible for them to think about it differently.  Maybe they it makes them think more ssssllloooowwwwwlllllyyyyy. Maybe it makes them stop thinking at all. Or maybe it  just makes them passive so we don't have to think about them at all. Or maybe - as my friend who knows these things says - they generally don't work.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But that's &lt;i&gt;not&lt;/i&gt; the point.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The point is: if an anorexic didn't believe he/she was fat, she wouldn't be an anorexic. She'd be a skinny person who knew she was too skinny and would do something about it - like eat some more.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So how do you change a belief?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Take football for example. The team which wins consistently believes that they can win. Not only that, they believe they can win this game. Right now. If they think they can't, they always lose.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What makes them believe this?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's pretty simple: they have a slogan, a mantra, a rallying cry, a &lt;i&gt;whatever&lt;/i&gt; to repeat over and over again. So as long as they can keep telling to themselves they can win, they will win, they're going to win - then they believe they can, will and are going to win.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Is a belief anything more than something we keep repeating to ourselves?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What happens when we stop talking to ourselves about one specific belief? Doesn't the alcoholic or a smoker keep reminding himself that he needs a drink or a cigarette? What would happen if he - instead - reminded himself that he needs an ice cream cone? (Besides getting fat and maybe getting diabetes) Wouldn't he eventually go from being an alcoholic to an ice cream-aholic?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A belief is just a thought. It's not made out of stone or steel or even jello. It's 'mind stuff'. There's two kinds of 'mind stuff'. There are memories and there's 'what I'm thinking now'.&lt;/div&gt;&lt;div&gt;All you can do with a memory is either lose it or drag it out to 'think about it now'. Everything you do and experience is the 'what I'm thinking now' stuff. That's where the anorexic and the alcoholic and the smoker 'belief' exists.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There isn't any automated thought loader which pushes thoughts into your 'thinker' and makes you think them. You get to pick and choose.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Don't believe it? Close your eyes and try to count the thoughts which come up over the next 10 seconds.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you're like I am, there were a lot of them. Ten, a hundred, I don't know. Just lots and lots of them. I'll bet you 'thought about' just a couple - maybe one or two. What happened to the rest of them? They're like the kids you &lt;i&gt;didn't&lt;/i&gt; pick to be on your team: they just wandered off.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The stuff you and I believe - about life, goodness, and - especially - ourselves - are just these familiar little thoughts we keep repeating. And by repeating them, we think their real. And that's all a &lt;i&gt;belief&lt;/i&gt; is.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So really, how hard is it to change a belief?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's easy - if you want to and are brave enough to give it up.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-4587166654603842392?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/4587166654603842392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=4587166654603842392' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/4587166654603842392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/4587166654603842392'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2010/08/change-again.html' title='Change - again'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-5690815049395947225</id><published>2010-06-20T13:02:00.004-06:00</published><updated>2010-08-02T08:46:30.914-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='musings'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='self help'/><title type='text'>Human Development - kind of</title><content type='html'>So somehow I went from wherever I was as a young guy to this worn out husk who had to deal with with raising six kids. Was nothing I planned to do, but, well, there it is.&lt;br /&gt;&lt;br /&gt;That's not the point - it's just to give you my credentials, assert my authority, bolster my claims, etc etc.&lt;br /&gt;&lt;br /&gt;This first point is that I'm writing from my experience - not text book theory or some other academic point of view [I have those also, but not about kids]&lt;br /&gt;&lt;br /&gt;Here's the Second Point:&lt;br /&gt;&lt;br /&gt;When a kid is just born, they don't do a lot and the way they interact is really different from how they are later on. They're kind of like little animals that just crawl or run around. They don't really argue about anything. Their complaints are very personal and immediate - hungry, wet, cold, lonesome, tired.&lt;br /&gt;&lt;br /&gt;After a couple of years something happens. You've been going along saying things like: Please don't do that or Please do this - and almost getting used to the fact that they never really pay much attention and don't seem to remember what you said from one second to the next. But then the thing happens: the kid turns around and looks you straight in the eye and says - very firmly and usually pretty loudly - "NO"!&lt;br /&gt;&lt;br /&gt;This is a major breakthrough.&lt;br /&gt;&lt;br /&gt;The kid hasn't turned into a monster or become a 'Terrible Two' (as I was told by my mother, over and over again). The kid just now finally noticed that you're trying to get him (or her) to do something that wasn't what he wanted to do.&lt;br /&gt;&lt;br /&gt;That's the point when you can &lt;span style="font-style: italic;"&gt;finally&lt;/span&gt; start teaching the kid how to 'not get run over by a car' and 'to clean your plate' and 'to pick up your toys'. It won't work - at least not for the first 10 or 20 years - but you can now get started and be (relatively) happy with the knowledge that you're not just being ignored. You're being Actively ignored and - believe it or not - all of you talking, pleading, reasoning, and (most of all) the example you set is sinking into that little mind.&lt;br /&gt;&lt;br /&gt;After mulling this over for a bunch of years - I've come to the conclusion that this is a pivotal point in all of our developments. It's the point where we realize that we live in a context over which we do not have total control and with which we &lt;span style="font-style: italic;"&gt;must&lt;/span&gt; learn to interact.&lt;br /&gt;&lt;br /&gt;And for a Third Point:&lt;br /&gt;&lt;br /&gt;Lora (we're married and four of the kids are her fault) is a certified Montessori method pre-primary instructor. She went to school for a year, did a year internship, read all of Montessori's books and practiced on our kids. Turns out that's enough for her - she prefers ponies and dogs to humans.&lt;br /&gt;&lt;br /&gt;Anyway, she has creds as well.&lt;br /&gt;&lt;br /&gt;Montessori discovered - by observing kids - that kids go through various phases of development where they are really different. She called them sensitive periods and it's fascinating stuff.&lt;br /&gt;&lt;br /&gt;But - to get to the point - there's one thing I wanted to write about here. It's the thing which happens when the fish in the classroom fish tank dies.&lt;br /&gt;&lt;br /&gt;The pre-primary Montessori classes have kids in the 3 to 5/6 year range. They generally have a fish tank. At some time during the year one or more of the fish will die.&lt;br /&gt;&lt;br /&gt;Here's where it gets interesting.&lt;br /&gt;&lt;br /&gt;The kids come in and quickly divide into two groups.&lt;br /&gt;&lt;br /&gt;The younger kids look at the fish and say 'the fish is dead' and then go do something.&lt;br /&gt;&lt;br /&gt;The older kids look at the fish and say 'the fish is dead. I wonder why the fish died. Was the water too hot? Was it too cold? Did another fish kill it? Wasn't the food right? I think that ...'&lt;br /&gt;&lt;br /&gt;You get the difference?&lt;br /&gt;&lt;br /&gt;Before something changes, it's ok to just see the dead fish and register it as a fact.&lt;br /&gt;&lt;br /&gt;After 'the change' we have to 'know Why'.&lt;br /&gt;&lt;br /&gt;I think this is the origin of Why.&lt;br /&gt;&lt;br /&gt;You should listen to some of the silly 'reasons' 5 and 6 year old kids come up with. Their logic is not all that bad, but the 'facts' they start from are pretty lame. But that makes sense because the don't have much experience.&lt;br /&gt;&lt;br /&gt;So do that for a while - - - and then - if you're brave - listen to some of your friends and neighbors talking about stuff. Things like 'the problem with ... is ... because ...'&lt;br /&gt;&lt;br /&gt;When I started listening to adults and comparing it with the stuff 5 and 6 year olds come up with, I got really upset. It's the same stuff!!!&lt;br /&gt;&lt;br /&gt;I think everybody is acting like 6 year olds - including the guys who run the countries and big companies.&lt;br /&gt;&lt;br /&gt;Doesn't that explain a lot of what's going on?&lt;br /&gt;&lt;br /&gt;I'm telling you - the problem is the whole thing is being run by 6 year olds and that's why nothing works. The answer is . . .&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-5690815049395947225?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/5690815049395947225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=5690815049395947225' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/5690815049395947225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/5690815049395947225'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2010/06/human-development-kind-of.html' title='Human Development - kind of'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-7115343596056238743</id><published>2010-06-20T12:19:00.006-06:00</published><updated>2010-06-20T13:02:02.473-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web Develoment'/><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='s/w opinions'/><category scheme='http://www.blogger.com/atom/ns#' term='CMS'/><title type='text'>ORM or Not? Part Two - Definitely Not</title><content type='html'>Maybe that's a little too harsh - but I don't think so.&lt;br /&gt;&lt;br /&gt;Here's the background:&lt;br /&gt;&lt;br /&gt;One of the biggest recurring programming problems I've had to deal with in site and application development has been - (drum roll) - developing the database. Not populating it - that's just boring. Developing and refining the data definitions.&lt;br /&gt;&lt;br /&gt;The "Conventional Wisdom" promulgated by Software Gurus is basically this:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Databases are Good With Data&lt;/li&gt;&lt;li&gt;Data Objects Are Good With Data&lt;/li&gt;&lt;li&gt;A Programmer Must Define a Mapping Between these Two Good Things and then All Will Be Good&lt;/li&gt;&lt;/ol&gt;Not my experience.&lt;br /&gt;&lt;br /&gt;Software Gurus don't write application. Software Gurus write Books and (occasionally) toy examples. So they really don't understand that Good does not generalize because the Good that Databases are with data is all about safety and accessing it in great and small piles. The Good that Data Objects are about is manipulation, fine structure, and flexibility.&lt;br /&gt;&lt;br /&gt;My experience with Object Relational Data Mapping - which is just a fancy phrase for how you get the data from the database into an object and back - is this: when I Did it Their Way, I had to hand-coordinate both my Objects and my Database.&lt;br /&gt;&lt;br /&gt;So when I wanted to add a field or change a field or change a datatype, I had to do everything twice.&lt;br /&gt;&lt;br /&gt;Now Rails has Active Record - which is a stupid Software Guru name for an ORM which creates the Data Objects automatically (my drivers license is an active record - meaning it's current so I can legally drive), but that doesn't 'solve the problem' it just moves it. [maybe Rails 3 is smarter,&lt;br /&gt;I dropped out just as Rails 2 was coming out]&lt;br /&gt;&lt;br /&gt;Specifically, the Rails solution moved the problem to 'migrations' which turned out to be fragile. I know: I tried it.&lt;br /&gt;&lt;br /&gt;So, a couple of years ago I proposed Not building an ORM, but rather loosening the coupling between the Database and the Data Objects.&lt;br /&gt;&lt;br /&gt;Here's what I've done:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Defined an PHP class which implements a data abstraction which includes most of the types of data and methods I want in my CMS [see &lt;a href="http://www.yasitekit.org/"&gt;http://www.yasitekit.org&lt;/a&gt;] and knows how to map those data types into database fields. It also knows how to create the database structures, create, update, delete, and retrieve those values.&lt;/li&gt;&lt;li&gt;Defined a PHP class which makes it easy (relatively speaking) to create objects which are instances of the data abstraction class. These classes come with a bunch of methods which I've found useful as well as a management class which &lt;span style="font-style: italic;"&gt;automatically&lt;/span&gt; provides interactive data administration.&lt;/li&gt;&lt;li&gt;Some automated analysis tools which work with this stuff so it's possible - and relatively painless and safe - to add, delete, and modify the derived objects (point 2) and reload the database. All done by hacking the derived PHP objects, but never ever touching SQL.&lt;/li&gt;&lt;li&gt;As a side benefit, I threw together a database adaptor which abstracts the 8 essential database operations [create/destroy database;create/drop table;insert,update,delete,select] at a level high enough that we never have to muck with SQL. This makes it possible to augment it with non-SQL databases - such as Mongodb. In it's present form it allows painless migration between sqlite, mysql, and postgresql (it currently handles 5 different PHP database interfaces - automatically figuring out what's available  - yada yada yada)&lt;/li&gt;&lt;/ol&gt;So, at this point, I feel more than comfortable saying No to ORM's.&lt;br /&gt;&lt;br /&gt;BTW - if you go to the &lt;a href="http://www.yasitekit.org/"&gt;YASiteKit&lt;/a&gt; site, you may be a little dissapointed because all of this good stuff is not available yet. But It Will Be - Real Soon Now (no kidding). And a whole lot more.&lt;br /&gt;&lt;br /&gt;What &lt;span style="font-style: italic;"&gt;is&lt;/span&gt; on the site is a pretty-much full set of documentation - both about the system design and about how each of the parts work [I write doc as I go, so it's not all pretty - but it's useful (I know because I use it)].&lt;br /&gt;&lt;br /&gt;So take a look. If you have any comments - let me know.&lt;br /&gt;&lt;br /&gt;Also, if you like it enough to want to help - let me know sooner - I'm almost ready to turn it loose to see if it gets any traction.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-7115343596056238743?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/7115343596056238743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=7115343596056238743' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7115343596056238743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7115343596056238743'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2010/06/orm-or-not-part-two-definitely-not.html' title='ORM or Not? Part Two - Definitely Not'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-8062044067988132425</id><published>2010-06-01T23:03:00.006-06:00</published><updated>2010-06-01T23:26:27.534-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='musings'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><title type='text'>Choices [Rant Warning]</title><content type='html'>I've been thinking a lot about the idea of Choice lately. Not so much any particular choice, but the whole idea itself and how it differentiates us from rocks and water and stuff like that.&lt;br /&gt;&lt;br /&gt;It seems to me that one of the distinguishing features of 'life' verses 'non-life' things is that 'living' things get to choose what they do rather than just follow the 'laws of nature'. For example, rocks don't do much of anything except just sit where they are or roll down hill or get knocked someplace else by something else, but a bug can get up and go someplace else - even against gravity, if it wants to.&lt;br /&gt;&lt;br /&gt;So what? Well, I've been wondering for a long time why we (that is us 'humans') do such stupid things and - even when we realize they are stupid and we are hurting ourselves - keep doing them. We even go so far as to tell ourselves - and everyone who will listen - how hard it is for us to not do them.&lt;br /&gt;&lt;br /&gt;Take eating too much. When I eat too much for a while, I get fat and crabby.  Then I feel sorry for myself because (I claim) it's oh, so hard to not eat too much. It sounds like there is an army of bad guys stuffing food into my mouth - but what's really happening is that I'm &lt;span style="font-style: italic;"&gt;choosing&lt;/span&gt; to pig out. It takes real effort to keep eating when I'm full or when I'm not really hungry.&lt;br /&gt;&lt;br /&gt;That one's simple and easy to see. And it's easy to see that if I'm fat, I made myself that way and I did it because I wanted to eat more than I wanted to feel good.&lt;br /&gt;&lt;br /&gt;But it goes a lot further than just eating.&lt;br /&gt;&lt;br /&gt;I think we've made up all kinds of religious garbage to excuse our disgusting behavior. We make up and believe in gods and devils and genetic forces and team loyalty and goals and success and all kinds of other junk to take the heat off of ourselves. 'The Devil tempted me - and I was weak',&lt;br /&gt;'It's in my Genes - I can't help myself', 'We've got to do it for the Team', ' .. or the Company', '... or our Kids', '... or for Honor', '... or Because That's the Kind of Man/Woman I Am'. etc&lt;br /&gt;&lt;br /&gt;It's all a smoke screen.&lt;br /&gt;&lt;br /&gt;We do it because that's what we choose to do - just like those guys who strap bombs on themselves and kill a bunch of people.&lt;br /&gt;&lt;br /&gt;It's a personal, misguided decision.&lt;br /&gt;&lt;br /&gt;The hell of it is, it isn't hard to Stop. It doesn't take Effort to &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; do something. There really isn't any force &lt;span style="font-style: italic;"&gt;making&lt;/span&gt; us do this stuff. Want proof? Just anethesize your mind somehow - and you won't be doing all that stuff you think is so hard to &lt;span style="font-style: italic;"&gt;not do&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;So let's get over it and stop kidding ourselves.&lt;br /&gt;&lt;br /&gt;We muck things up, piss each other off, get mad about stuff, drill oil wells places where we can't plug leaks, kill people, destroy the whole bloody planet and everything on it because we choose to.&lt;br /&gt;&lt;br /&gt;That's all there is to it.&lt;br /&gt;&lt;br /&gt;And that's what makes us different from a nice, peaceful rock.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-8062044067988132425?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/8062044067988132425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=8062044067988132425' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8062044067988132425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8062044067988132425'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2010/06/choices.html' title='Choices [Rant Warning]'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-979292876320622304</id><published>2010-05-06T15:10:00.007-06:00</published><updated>2010-05-06T15:40:01.530-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='musings'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><title type='text'>Understanding</title><content type='html'>&lt;span style="font-weight: bold;font-family:lucida grande;font-size:130%;"  &gt;To Understand, to Have Understanding, to Know&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What does it mean when we say "I understand"?&lt;br /&gt;&lt;br /&gt;Like everybody else - or at least I &lt;span style="font-style: italic;"&gt;think&lt;/span&gt; everybody else - I used to take it for granted. I thought that I knew what it meant.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Here's what I've figured out so far.&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:lucida grande;font-size:130%;"  &gt;&lt;span style="font-weight: bold;"&gt;Thinking&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First of all, we seem to think that we think.&lt;br /&gt;&lt;br /&gt;Some of us think we think "rationally", but most of us have no idea what that actually means.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Somehow we've latched on to 'logic' as 'real thinking' and everything else as some sort of minor annoyance.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;And here's why:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Logic - a Necessary Digression&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;First, what it isn't.&lt;br /&gt;&lt;br /&gt;Logic is &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; sticking 'because' in the middle of sentences. It's not making up 'reasons' for things. And it's not asking and then answering 'why'?&lt;br /&gt;&lt;br /&gt;Logic is a rigorous, formal method of evaluating the Truth or Falseness of sentences which are constructed according to specific rules.&lt;br /&gt;&lt;br /&gt;First of all, what is a sentence?&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Let's get formal:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;P, Q, and R are all propositions or sentences - which means they have truth values.&lt;/li&gt;&lt;li&gt;* AND, OR, and IMPLIES are connectives&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;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:&lt;br /&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;if P and Q are both True, then P AND Q is True, otherwise it's False&lt;/li&gt;&lt;li&gt;if P and Q are both False, then P OR Q is False, otherwise it's True&lt;/li&gt;&lt;li&gt;if P is True and Q is True or if P is False, then P IMPLIES Q is True, otherwise it's False&lt;/li&gt;&lt;li&gt;if P is True, then NOT P is False and if P is False, then NOT P is True.&lt;/li&gt;&lt;/ul&gt;If we add in some Parentheses, we can get really wild and use sentences for propositions and write things like:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;((P AND Q) OR ((NOT R) OR S)) IMPLIES Z&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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 &lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;P AND Q OR NOT R OR S IMPLIES Z&lt;/span&gt;&lt;/blockquote&gt;means &lt;span style="font-family:courier new;"&gt;(P AND (Q OR (NOT R)) ) OR (S IMPLIES Z)&lt;/span&gt; or the thing I wrote above.&lt;br /&gt;&lt;br /&gt;But that's for really studying 'Propositional Logic' - which you can find in a book. For now, it's not really important.&lt;br /&gt;&lt;br /&gt;The important thing is this:&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Everything you write using Logic can be traced back to and completely depends on the Axioms - the Propositions you write down and start from.&lt;br /&gt;&lt;br /&gt;This means that Logic &lt;span style="font-style: italic;"&gt;only&lt;/span&gt; transforms the shape of the original propositions. It &lt;span style="font-style: italic;"&gt;can't&lt;/span&gt; add anything new.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;This lets us write richer sentences because we can then write things like: &lt;span style="font-family:courier new;"&gt;All P is True&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;At Least One P is True&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Having quantifiers makes is easy to tell when someone is saying something stupid. For example, if somebody says &lt;span style="font-style: italic;"&gt;"All cats are mean"&lt;/span&gt;, 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 &lt;span style="font-style: italic;"&gt;really&lt;/span&gt; meant &lt;span style="font-style: italic;"&gt;"most cats are mean"&lt;/span&gt;. That is supposed to make it better, but it really&lt;br /&gt;means that they don't &lt;span style="font-style: italic;"&gt;really&lt;/span&gt; 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.&lt;br /&gt;&lt;br /&gt;Also, it helps tell what you can know for sure. For example, when somebody says &lt;span style="font-style: italic;"&gt;"you can't do that"&lt;/span&gt;, but you think it would be a good idea to &lt;span style="font-style: italic;"&gt;"do that"&lt;/span&gt;, all you need to do to prove that&lt;br /&gt;it's possible to &lt;span style="font-style: italic;"&gt;"do that"&lt;/span&gt; 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 &lt;span style="font-style: italic;"&gt;"won't work"&lt;/span&gt;, but if you can find an example of when &lt;span style="font-style: italic;"&gt;"it worked"&lt;/span&gt;, you can ignore them because you know it's possible.&lt;br /&gt;&lt;br /&gt;There are a lot of things like that.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:lucida grande;font-size:100%;"  &gt;So Why Logic?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Logic can keep us out of trouble. It can help us predict if something will work or if it won't.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Logic is reliable.&lt;br /&gt;&lt;br /&gt;Why is logic so reliable?&lt;br /&gt;&lt;br /&gt;Not magic: Logic is a bunch of rules for figuring out if things will work based on thousands of years of experience.&lt;br /&gt;&lt;br /&gt;So Logic is the Answer!&lt;br /&gt;&lt;br /&gt;Right?&lt;br /&gt;&lt;br /&gt;Wrong!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:lucida grande;font-size:130%;"  &gt;Propositions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Where do the Propositions come from?&lt;br /&gt;&lt;br /&gt;Remember, the Logic just &lt;span style="font-style: italic;"&gt;transforms&lt;/span&gt; our propositions - our axioms - our guesses of what is right or wrong.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Crap is still Crap.&lt;br /&gt;&lt;br /&gt;One place our Propositions don't come from is 'reason' or 'logic'. We get them by following some other rules.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-family: georgia;font-family:lucida grande;font-size:100%;"  &gt;Scientific Propositions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One set of rules are the ones used in Science: a fact is an independently, verifiable experimental result.&lt;br /&gt;&lt;br /&gt;Let's take that apart:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;/ul&gt;This is pretty restrictive. It's also pretty slow and pretty expensive. It's also pretty good at building reliable knowledge.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;How else can we come up with a Proposition?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-family: georgia;font-family:lucida grande;" &gt;Guesses&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;How about we just guess?&lt;br /&gt;&lt;br /&gt;Guessing is good. We do it all the time. Most of the time it doesn't work though.&lt;br /&gt;&lt;br /&gt;But often, it's all we have.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-family: georgia;font-family:lucida grande;" &gt;Emotional Propositions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;How about we just claim something we want to be trueactually is?&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;When we do that and use 'Logic', we call that 'Rationalizing'.&lt;br /&gt;&lt;br /&gt;We're 'just making up reasons for what we want to do'.&lt;br /&gt;&lt;br /&gt;This is how a lot of real disasters are created.&lt;br /&gt;&lt;br /&gt;Take starting a war.&lt;br /&gt;&lt;br /&gt;Does it really make sense to rip everything apart, destroy somebody else's hard work, their lives, etc etc?&lt;br /&gt;&lt;br /&gt;Sure - if you're willing to cause that much pain and you want their stuff.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;But enough of this&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:lucida grande;font-size:130%;"  &gt;&lt;span style="font-weight: bold;"&gt;Back to Thinking&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I think you'll agree that - looked at this way - rational thought isn't really much 'higher' than any other form of 'thought'.&lt;br /&gt;&lt;br /&gt;We're really just kidding ourselves.&lt;br /&gt;&lt;br /&gt;So what is all this 'thinking' and 'understanding'.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:lucida grande;" &gt;What I 'think' about 'understanding'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Sounds pretty good - doesn't it.&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:lucida grande;font-size:100%;"  &gt;&lt;span style="font-weight: bold;"&gt;What Happens if things happen like I Predict?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Does that mean that I can make accurate predictions?&lt;br /&gt;&lt;br /&gt;Experience says: Well, Maybe. It all depends.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:lucida grande;" &gt;What Happens if things don't happen like I expect?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Well, lots of things.&lt;br /&gt;&lt;br /&gt;Mostly I used to ask Why?&lt;br /&gt;&lt;br /&gt;Then I'd come up with some Propositions to use to build a logical argument explaining how what I understood&lt;span style="font-style: italic;"&gt; should&lt;/span&gt; have happened, but didn't.&lt;br /&gt;&lt;br /&gt;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 . . .)&lt;br /&gt;&lt;br /&gt;Then I'd can feel comfortable again because I'd 'know why it happened that way'.&lt;br /&gt;&lt;br /&gt;In other words, I'd 'understand'.&lt;br /&gt;&lt;br /&gt;(I know you would never do anything like this. You understand things a lot better than I do - don't you?)&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:lucida grande;font-size:130%;"  &gt;&lt;span style="font-weight: bold;"&gt;And So, . . .&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It's just one big circle of self delusion.&lt;br /&gt;&lt;br /&gt;If you believe this stuff, you probably feel uncomfortable.&lt;br /&gt;&lt;br /&gt;So even if you know it's true, you won't feel that you 'understand' it and will want to try.&lt;br /&gt;&lt;br /&gt;See the trap?&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;(c) Copyright 2010 Mike Howard. All Rights Reserved.&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/3666775354459763953-979292876320622304?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/979292876320622304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=979292876320622304' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/979292876320622304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/979292876320622304'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2010/05/understanding.html' title='Understanding'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-7013371876934109002</id><published>2010-04-23T09:59:00.004-06:00</published><updated>2010-04-23T10:38:41.074-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='s/w opinions'/><title type='text'>Timing Tests</title><content type='html'>OK - I'm &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; a timing test expert. I'm &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; a program profiling expert. etc etc etc&lt;br /&gt;&lt;br /&gt;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 . . .'&lt;br /&gt;&lt;br /&gt;But I don't really care about 'doing it "right"' according to some picky standard.&lt;br /&gt;&lt;br /&gt;What I do care about is not writing really slow code.&lt;br /&gt;&lt;br /&gt;For that, the rules are simple:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Rule 1&lt;/span&gt;: Don't do things that take a long time&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Rule 2&lt;/span&gt;: 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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Rule 1 - expanded:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Here are the relevant cases:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Monolithic program doing in-memory data access/processing&lt;br /&gt;&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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 &lt;span style="font-style: italic;"&gt;really&lt;/span&gt; slows things down, because &lt;span style="font-style: italic;"&gt;parsing strings takes a lot of repetitive work. That's why we have compilers!&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;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&lt;/li&gt;&lt;li&gt;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.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;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 &lt;span style="font-style: italic;"&gt;relative to in-memory and disk i/o&lt;/span&gt;.&lt;/li&gt;&lt;/ol&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Rule 2 - expanded&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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).&lt;br /&gt;&lt;br /&gt;So I have lots of functions that look like:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;function __get($name) {&lt;br /&gt;if (in_array($name, array('foo', 'bar', 'baz'))) {&lt;br /&gt;  return $this-&gt;$name;&lt;br /&gt;}else {&lt;br /&gt;  throw new Exception("$name is not a valid attribute name");&lt;br /&gt;}&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;or&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;function __get($name) {&lt;br /&gt;if (($name == 'foo' || $name == 'bar' || $name == 'baz'))) {&lt;br /&gt;  return $this-&gt;$name;&lt;br /&gt;}else {&lt;br /&gt;  throw new Exception("$name is not a valid attribute name");&lt;br /&gt;}&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;or&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;function __get($name) {&lt;br /&gt;switch ($name) {&lt;br /&gt;  case 'foo':&lt;br /&gt;  case 'bar':&lt;br /&gt;  case  'baz':&lt;br /&gt;    return $this-&gt;$name;&lt;br /&gt;  default:&lt;br /&gt;    throw new Exception("$name is not a valid attribute name");&lt;br /&gt;}&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;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'.&lt;br /&gt;&lt;br /&gt;To do this, I need to build a test case and run it to get some timing numbers.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Here's what I got:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;switch: 49.7731 seconds&lt;br /&gt;&lt;/li&gt;&lt;li&gt;in_array method: 86.3004 seconds&lt;br /&gt;&lt;/li&gt;&lt;li&gt;if with complex conditional: 57.0134 seconds&lt;/li&gt;&lt;/ul&gt;Guess which method I'm going with.&lt;br /&gt;&lt;br /&gt;[guess how I'm going to refactor a lot of my code (sigh - I should have tested &lt;span style="font-style: italic;"&gt;first&lt;/span&gt;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-7013371876934109002?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/7013371876934109002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=7013371876934109002' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7013371876934109002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7013371876934109002'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2010/04/timing-tests.html' title='Timing Tests'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-3455525412384646572</id><published>2010-04-19T14:11:00.008-06:00</published><updated>2010-04-19T15:53:23.262-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='musings'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><title type='text'>Self Image, Self Identity and All That</title><content type='html'>Who am I?&lt;br /&gt;&lt;br /&gt;Or, more to the point, what is the 'idea' of myself that I identify with?&lt;br /&gt;&lt;br /&gt;Or, even more to the point, how do I 'like' to think about myself?&lt;br /&gt;&lt;br /&gt;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'.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;That's the setup. Now, here are some questions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Am I nothing more than an opinion? Or am I real?&lt;/li&gt;&lt;li&gt;Can I change 'Who I am' by changing my opinion?&lt;/li&gt;&lt;li&gt;Is my 'World View' a result of 'Who I am' or is it something I create for my 'Who I am' to live in?&lt;/li&gt;&lt;li&gt;Do I see and hear the world around me OR do I pick and choose what I hear and know?&lt;/li&gt;&lt;li&gt;Do I really know 'Who I am'?&lt;/li&gt;&lt;li&gt;Do I really know my friends? Or do I make them supporting actors for myself?&lt;/li&gt;&lt;li&gt;Can I live without knowing 'Who I am'?&lt;/li&gt;&lt;li&gt;How can I avoid living in an Illusion if I continue to 'know' 'Who I am'?&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;First Hypothetical&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let's suppose that 'Who I am' is an opinion.&lt;br /&gt;&lt;br /&gt;Opinions are just ideas that can be changed. They aren't 'facts'.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;I'll just have a different 'opinion'.&lt;br /&gt;&lt;br /&gt;So, with my different opinion, won't the World be different?&lt;br /&gt;&lt;br /&gt;Won't my friends become different people?&lt;br /&gt;&lt;br /&gt;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?&lt;br /&gt;&lt;br /&gt;All I need do to test this is genuinely change my opinion &lt;span style="font-style: italic;"&gt;once&lt;/span&gt; and see if this is what happens.&lt;br /&gt;&lt;br /&gt;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?&lt;br /&gt;&lt;br /&gt;Do I want to know?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Second Hypothetical&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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]&lt;br /&gt;&lt;br /&gt;So how will this effect my World View? How will I tend to filter and interpret that which I see?&lt;br /&gt;&lt;br /&gt;Isn't is natural for me look for the evil and bad - so I am - in contrast - much better 'than average'?&lt;br /&gt;&lt;br /&gt;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'?&lt;br /&gt;&lt;br /&gt;How can we test this?&lt;br /&gt;&lt;br /&gt;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?&lt;br /&gt;&lt;br /&gt;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?&lt;br /&gt;&lt;br /&gt;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?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Third Hypothetical&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Again, suppose 'Who I am' is an opinion.&lt;br /&gt;&lt;br /&gt;Then there must be something which has that opinion.&lt;br /&gt;&lt;br /&gt;That something must be able to observe - inasmuch as it has thoughts, the 'opinion' being one of them.&lt;br /&gt;&lt;br /&gt;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).&lt;br /&gt;&lt;br /&gt;If this is true, then 'Who I am' is an opinion and the 'something' can become aware of this.&lt;br /&gt;&lt;br /&gt;How can we test this?&lt;br /&gt;&lt;br /&gt;Can we watch our own thoughts? As we think them?&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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?&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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?&lt;br /&gt;&lt;br /&gt;Is the dwelling on 'the bad things' and 'how sick I am' the &lt;span style="font-style: italic;"&gt;cure&lt;/span&gt; or the &lt;span style="font-style: italic;"&gt;cause&lt;/span&gt; of disease and despair?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Fourth Hypothetical&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;'Who I am' and 'Who You are' are different.&lt;br /&gt;&lt;br /&gt;It doesn't matter if they are real or just opinions.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;But mine is different from yours, so our 'worlds' are different.&lt;br /&gt;&lt;br /&gt;Can I really see 'Who You are'?&lt;br /&gt;&lt;br /&gt;Can I do more than guess?&lt;br /&gt;&lt;br /&gt;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)?&lt;br /&gt;&lt;br /&gt;So how can I ever see where you don't make my 'Who I am' good and right? And can you see me?&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Doesn't that prove we can never know each other?&lt;br /&gt;&lt;br /&gt;How can we converse?&lt;br /&gt;&lt;br /&gt;Aren't we having two meaningless conversations with ourselves while we pretend that the other is there?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Fifth Hypothetical&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Doesn't this mean that I've been living in an illusion?&lt;br /&gt;&lt;br /&gt;Can I escape the illusion without giving up this expectation, this prediction of the future?&lt;br /&gt;&lt;br /&gt;Realizing this, can I continue to maintain the illusion - knowing it is a lie?&lt;br /&gt;&lt;br /&gt;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?&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;Copyright Mike Howard,  2010. All rights reserved.&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-3455525412384646572?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/3455525412384646572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=3455525412384646572' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/3455525412384646572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/3455525412384646572'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2010/04/self-image-self-identity-and-all-that_19.html' title='Self Image, Self Identity and All That'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-8688967469185383506</id><published>2010-04-10T09:20:00.003-06:00</published><updated>2010-04-19T15:53:47.817-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>News Flash: PHP Documenters Insane!!!!</title><content type='html'>The PHP documentation has gone from very useful to hideously obstructive.&lt;br /&gt;&lt;br /&gt;The people who are rearranging the doc into little, tiny chunks which are hyperlinked all over the place obviously never write code.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Old Doc:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;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.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;New Doc:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Go to the index click on Predefined Exceptions&lt;/li&gt;&lt;li&gt;Click on Exception - find description of Exception Object - info not there&lt;/li&gt;&lt;li&gt;Back Button&lt;/li&gt;&lt;li&gt;Click on Error Exception - find description of Generic ErrorExeption object&lt;/li&gt;&lt;li&gt;Back Button&lt;/li&gt;&lt;li&gt;Click on SPL Exceptions (what the hell is this? - something new?)&lt;/li&gt;&lt;li&gt;Look at Table of contents: 13 Exception Categories - none of which&lt;/li&gt;&lt;li&gt; looks like an IOException&lt;/li&gt;&lt;li&gt;Click on Predefined Exceptions in the See Also -&lt;/li&gt;&lt;li&gt;  Back to Previous Useless Page - And Repeat&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;First they completely screw up the Perl Regular Expression page by chopping it into tiny, obscure chunks and now you destroy the exception documentation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;To the PHP Documentation Project:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;PLEASE&lt;/span&gt; put it back the way it was.&lt;br /&gt;&lt;br /&gt;Or get somebody who actually uses this stuff like a handbook while writing code to fix it&lt;br /&gt;&lt;br /&gt;Or shoot somebody.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;To Everybody Else:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Maybe the documentation people have stock in a book company and want the reference books to succeed by making the online Doc unusable?&lt;br /&gt;&lt;br /&gt;All I can say is that the way they are going is really going to help Rails and Django.&lt;br /&gt;&lt;br /&gt;What do you think?&lt;br /&gt;&lt;br /&gt;P.S. Please Send a Nasty Note to the Gods of PHP&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-8688967469185383506?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/8688967469185383506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=8688967469185383506' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8688967469185383506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8688967469185383506'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2010/04/news-flash-php-documenters-insane.html' title='News Flash: PHP Documenters Insane!!!!'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-7492378604608079230</id><published>2010-01-28T21:17:00.004-07:00</published><updated>2010-04-19T15:56:39.610-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='s/w opinions'/><title type='text'>Why are our Programming Languages so Bad?</title><content type='html'>I just took a quick look at Scala and Lua . . . and I don't think either one is a winner, but for different reasons.&lt;br /&gt;&lt;br /&gt;The Scala guys seem to have fallen into the arcane syntax trap - with lots of critical information inferred. I think I agree with this &lt;a href="http://creativekarma.com/ee.php/weblog/comments/my_verdict_on_the_scala_language/"&gt;blog post&lt;/a&gt; from January, 2008: Scala is probably not a readable language.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;The simple fact is that none of the modern languages are any good. They all suck.&lt;br /&gt;&lt;br /&gt;Why is that?&lt;br /&gt;&lt;br /&gt;We really know a lot about language design by now - or at least we should.&lt;br /&gt;&lt;br /&gt;One of the things which really irritates me is that every damned language uses different syntax for the &lt;span style="font-style: italic;"&gt;same&lt;/span&gt; semantic concept. I don't think I know of two languages which implement &lt;span style="font-weight: bold;"&gt;if ... else-if ... else ...&lt;/span&gt; the same way. [else-if is spelled 'elif', 'elsif', 'elseif', or 'else if' or doesn't exist].&lt;br /&gt;&lt;br /&gt;It is now a &lt;span style="font-weight: bold;"&gt;fact&lt;/span&gt; that programmers work in &lt;span style="font-style: italic;"&gt;multiple&lt;/span&gt; languages. These &lt;span style="font-style: italic;"&gt;stupid, unnecessary&lt;/span&gt; syntax inconsistencies make life hell.&lt;br /&gt;&lt;br /&gt;I'm starting a list of what should be in a modern language:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;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.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;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.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Global variables are Evil. Crockford is right: They should not exist.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;String handling is Good. If you don't think it's a necessity - go write some string handling in C for a few years.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;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].&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;Functions need to be 1st class things. In fact, everything needs to be.&lt;/li&gt;&lt;li&gt;Closures are Good - we need them.&lt;/li&gt;&lt;li&gt;Functional programming is good - We need it.&lt;/li&gt;&lt;li&gt;Imperative Programming - Structured style [like Dykstra told us] is good - we need it too.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;Interpreted is Good. It makes writing code much faster. Must have a REPL.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;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 &lt;span style="font-style: italic;"&gt;clarity.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;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 &lt;span style="font-weight: bold;"&gt;vi&lt;/span&gt; from time to time. I've tried Eclipse, but just couldn't deal with it. I think this is a non-issue &lt;span style="font-style: italic;"&gt;except&lt;/span&gt; that the Language should support development &lt;span style="font-style: italic;"&gt;without&lt;/span&gt; and IDE.&lt;/li&gt;&lt;li&gt;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 &lt;span style="font-weight: bold;"&gt;print foo.__doc__&lt;/span&gt;. It saves lots and lots of time paging through documentation. There is also a builtin function called &lt;span style="font-weight: bold;"&gt;dir()&lt;/span&gt; which generates a &lt;span style="font-style: italic;"&gt;sorted&lt;/span&gt; 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.&lt;/li&gt;&lt;li&gt;Automatic Document Generation is Good - but the current systems stink. They are like a tail wagging a dog: Code is &lt;span style="font-style: italic;"&gt;always&lt;/span&gt; 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.&lt;/li&gt;&lt;li&gt;To be Continued&lt;/li&gt;&lt;/ol&gt;Any Things to add to the list?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-7492378604608079230?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/7492378604608079230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=7492378604608079230' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7492378604608079230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7492378604608079230'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2010/01/why-are-our-programming-languages-so.html' title='Why are our Programming Languages so Bad?'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-8306978422302463247</id><published>2010-01-12T19:15:00.003-07:00</published><updated>2010-01-12T19:24:06.709-07:00</updated><title type='text'>Apple Non-Useability. Is Apple Copying Microsoft?</title><content type='html'>I don't get it&lt;br /&gt;&lt;br /&gt;Apple folks almost invented Usability testing and analysis. Tog, Nielsen, whoever else.&lt;br /&gt;&lt;br /&gt;I just upgraded to Snow Leopard. It runs faster but . . .&lt;br /&gt;&lt;br /&gt;- 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?&lt;br /&gt;&lt;br /&gt;- 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 &lt;span style="font-style: italic;"&gt;we&lt;/span&gt; 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'.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;There's more, but that's more than enough carping for now.&lt;br /&gt;&lt;br /&gt;Apple is getting closer to being the New Microsoft.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-8306978422302463247?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/8306978422302463247/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=8306978422302463247' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8306978422302463247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8306978422302463247'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2010/01/apple-non-useability-is-apple-copying.html' title='Apple Non-Useability. Is Apple Copying Microsoft?'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-7418029310289740499</id><published>2009-10-16T09:43:00.006-06:00</published><updated>2010-04-23T10:41:37.011-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Missing Method in Python</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Preamble&lt;/span&gt; - optional&lt;br /&gt;&lt;br /&gt;Ruby has a whole boat load of methods which allow a programmer to overload and override all kinds of stuff. One of them is '&lt;span style="font-weight: bold;"&gt;method_missing'&lt;/span&gt;, which is a method which is called if you invoke 'foo.bar()' and 'bar' is not the name of a method in 'foo'.&lt;br /&gt;&lt;br /&gt;The Rails folks use it to transform function names like: &lt;span style="font-family:courier new;"&gt;find_foo_by_date_and_color(date, color)&lt;/span&gt; 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.&lt;br /&gt;&lt;br /&gt;You probably get from this that I think the Rails people overuse things like &lt;span style="font-weight: bold;"&gt;method_missing&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;You're right.&lt;br /&gt;&lt;br /&gt;But that doesn't mean it isn't useful.&lt;br /&gt;&lt;br /&gt;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 &lt;span style="font-weight: bold;"&gt;method_missing&lt;/span&gt; (at least they don't seem to admit it - as far as I was able to find)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Problem&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm writing a little local HTTP server for my YASiteKit CMS/web-site kit thing (&lt;a href="http://yasitekit.org/"&gt;http://yasitekit.org&lt;/a&gt;) 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 &lt;span style="font-weight: bold;"&gt;readline()&lt;/span&gt; - which are used in the bowels of the HTTP server library.&lt;br /&gt;&lt;br /&gt;The 'obvious solution' is to wrap the SSLSocket in something which adds the necessary methods.&lt;br /&gt;&lt;br /&gt;But I'm lazy - in a sense - and decided to try to do this using a Pythonic equivalent to Ruby's missing method machinery.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;look up the attribute&lt;/li&gt;&lt;li&gt;call it with arguments&lt;/li&gt;&lt;/ol&gt;So the solution is easy:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;wrap the object by passing it to the object constructor&lt;/li&gt;&lt;li&gt;create a __getattr__() method which returns &lt;span style="font-weight: bold;"&gt;getattr(wrapped-instance, method-name)&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;the Python interpreter then completes the call, with arguments, on the bound method.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;If the method exists in &lt;span style="font-weight: bold;"&gt;wrapped-instance&lt;/span&gt;, then the returned value is the method, bound to the wrapped-instance. If not, then &lt;span style="font-weight: bold;"&gt;wrapped-instance&lt;/span&gt; throws an AttributeError exception.&lt;br /&gt;&lt;br /&gt;It doesn't interfere with the wrapper's methods because __getattr__() is only called if the attribute is not found.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Here's the sample code I wrote to verify the method:&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;blockquote&gt;class Floof(object):&lt;br /&gt;var = 'This is Floof'&lt;br /&gt;def __init__(self, var):&lt;br /&gt;self.var = var&lt;br /&gt;def func(self, var):&lt;br /&gt;print('\nThis is Floof.func called on self')&lt;br /&gt;print('Floof.var: ', Floof.var)&lt;br /&gt;print('Floof.self.var: ', self.var)&lt;br /&gt;print('Floof.func(var): ', var)&lt;br /&gt;&lt;br /&gt;class Foo(object):&lt;br /&gt;var = 'This is Foo'&lt;br /&gt;def __init__(self, var, floof_instance):&lt;br /&gt;self.var = var&lt;br /&gt;self.floof_instance = floof_instance&lt;br /&gt;def __getattr__(self, name):&lt;br /&gt;print('\nFoo.__getattr__(%s) called' % name)&lt;br /&gt;return getattr(self.floof_instance, name)&lt;br /&gt;raise AttributeError('Foo instance: Attribute %s not found' % name)&lt;br /&gt;def foo_func(self, var):&lt;br /&gt;print('\nThis is Foo.func called on self')&lt;br /&gt;print('Foo.var: ', Foo.var)&lt;br /&gt;print('Foo.self.var: ', self.var)&lt;br /&gt;print('Foo.foo_func(var): ', var)&lt;br /&gt;def wrapped_func(self, var):&lt;br /&gt;print('\nI\'m wrapping Floof.func()')&lt;br /&gt;self.floof_instance.func(var)&lt;br /&gt;&lt;br /&gt;floof = Floof('I\'m a Floof')&lt;br /&gt;floof.func('calling floof.func() directly')&lt;br /&gt;foo = Foo('I\'m a Foo', floof)&lt;br /&gt;foo.foo_func('calling foo.foo_func() directly')&lt;br /&gt;foo.func('calling floof.func() through Foo wrapper')&lt;br /&gt;foo.wrapped_func('calling floof.func() via a wrapper method')&lt;br /&gt;foo.flob('calling foo.flob() which does not exist')&lt;br /&gt;&lt;/blockquote&gt;&lt;/span&gt;Here's the output:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;This is Floof.func called on self&lt;br /&gt;('Floof.var: ', 'This is Floof')&lt;br /&gt;('Floof.self.var: ', "I'm a Floof")&lt;br /&gt;('Floof.func(var): ', 'calling floof.func() directly')&lt;br /&gt;&lt;br /&gt;This is Foo.func called on self&lt;br /&gt;('Foo.var: ', 'This is Foo')&lt;br /&gt;('Foo.self.var: ', "I'm a Foo")&lt;br /&gt;('Foo.foo_func(var): ', 'calling foo.foo_func() directly')&lt;br /&gt;&lt;br /&gt;Foo.__getattr__(func) called&lt;br /&gt;&lt;br /&gt;This is Floof.func called on self&lt;br /&gt;('Floof.var: ', 'This is Floof')&lt;br /&gt;('Floof.self.var: ', "I'm a Floof")&lt;br /&gt;('Floof.func(var): ', 'calling floof.func() through Foo wrapper')&lt;br /&gt;&lt;br /&gt;I'm wrapping Floof.func()&lt;br /&gt;&lt;br /&gt;This is Floof.func called on self&lt;br /&gt;('Floof.var: ', 'This is Floof')&lt;br /&gt;('Floof.self.var: ', "I'm a Floof")&lt;br /&gt;('Floof.func(var): ', 'calling floof.func() via a wrapper method')&lt;br /&gt;&lt;br /&gt;Foo.__getattr__(flob) called&lt;br /&gt;&lt;br /&gt;AttributeError: 'Floof' object has no attribute 'flob'&lt;br /&gt;&lt;br /&gt;function __getattr__ in missingmethod.py at line 52&lt;br /&gt;return getattr(self.floof_instance, name)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;See - It works!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-7418029310289740499?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/7418029310289740499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=7418029310289740499' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7418029310289740499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7418029310289740499'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2009/10/missing-method-in-python.html' title='Missing Method in Python'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-1469984825708102352</id><published>2009-07-14T09:53:00.005-06:00</published><updated>2010-04-19T15:53:23.263-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='musings'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><title type='text'>A Story</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Herman&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;by Mike Howard, (c) 2009&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;How it Started&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The day the Lemmings ran over the cliff, Herman forgot and went to the park.&lt;br /&gt;&lt;br /&gt;When it got dark, he went home – but there was nobody there. That’s when he remembered about the Big Cliff Run.&lt;br /&gt;&lt;br /&gt;They were all dead now.&lt;br /&gt;&lt;br /&gt;That’s the way it is with Lemmings. He remembered.&lt;br /&gt;&lt;br /&gt;Then he cried.&lt;br /&gt;&lt;br /&gt;The next morning, when he got up, Herman remembered.&lt;br /&gt;&lt;br /&gt;He couldn’t understand what had happened. All his life he’d been taught how to be a good Lemming. Maybe he wasn’t a Lemming?&lt;br /&gt;&lt;br /&gt;He felt himself. Felt like a Lemming.&lt;br /&gt;&lt;br /&gt;He looked in the mirror. Looked like a Lemming.&lt;br /&gt;&lt;br /&gt;He was hungry – just like always – and just like a Lemming.&lt;br /&gt;&lt;br /&gt;Then how come he’d forgotten the Big Cliff Run? Wasn’t that supposed to be Instinct? Wasn’t it built into his Jeans? (or was it Genes?) Wasn’t it Inescapable and the Source of All Sorrow?&lt;br /&gt;&lt;br /&gt;How could he just forget something that was as much a part of him as his nose?&lt;br /&gt;&lt;br /&gt;Something was wrong.&lt;br /&gt;&lt;br /&gt;So Herman set of to see Marvin – the big, bulky Lemming On the Hill. Marvin knew everything. Marvin knew all the Old Stories from the Old Times by the Old Lemmings who Knew Everything. Marvin was a Great and Good Lemming. The Greatest and Goodest.&lt;br /&gt;&lt;br /&gt;Marvin was so Good that he didn’t go on the Big Cliff Run. It made him ever so miserable not to Go – to hold himself back – but he did it for the Good of Every Lemming!&lt;br /&gt;&lt;br /&gt;He had to. He couldn’t let Lemmingness be Lost! Someone had to sacrifice for the Good of All Lemmings. Someone had to tell the Stories. Someone had to make sure All the Lemmings made the Big Cliff Run.&lt;br /&gt;&lt;br /&gt;It was a Heavy Burden, but Marvin kept the Faith and Did His Duty.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Marvin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Marvin wasn’t happy to see Herman. In fact he frowned and said something Herman hadn’t ever heard before (which was good, because then Herman didn’t understand what it meant and didn’t know how angry Marvin was).&lt;br /&gt;&lt;br /&gt;“What happened,” Marvin asked.&lt;br /&gt;&lt;br /&gt;Herman blushed under his fur. “I just forgot,” he said.&lt;br /&gt;&lt;br /&gt;”!!!!!,” Marvin exploded!!!!&lt;br /&gt;&lt;br /&gt;Herman stuttered, “I just woke up and it was so nice and sunny and so I though ‘I’ll go to the park’ and I didn’t think anything else and so I went and it was nice and the birds were out and singing and the grass was soft and . . .” It all came out in a rush.&lt;br /&gt;&lt;br /&gt;Marvin glowered.&lt;br /&gt;&lt;br /&gt;“Don’t you remember your lessons?” he asked. “Didn’t I tell you to repeat the Lemming Mantra every morning and every night?” “Didn’t I”&lt;br /&gt;&lt;br /&gt;“Yes,” said Herman.&lt;br /&gt;&lt;br /&gt;“Well? . . .”&lt;br /&gt;&lt;br /&gt;“I just forgot. It was such a nice day, . . . and I just forgot,” Herman said lamely.&lt;br /&gt;&lt;br /&gt;“Hmmph!!!” said Marvin.&lt;br /&gt;&lt;br /&gt;As Herman trudged down the hill he saw Lonny, Marvin’s apprentice and student dragging a big bag of Cheetos up the hill. Marvin was too fat (oops! too important) to go get his own food, so everyone brought him what he needed. Lonny and Marvin were great Lemmings to hold themselves back and stay alive year after year, thought Herman.&lt;br /&gt;&lt;br /&gt;Sighing, Herman walked slowly home.&lt;br /&gt;&lt;br /&gt;“I’ll remember Next Year,” he though as he sadly trudged along.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Interlude&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Over the next year, the few surviving Lemmings rebuilt. They had new babies who quickly grew up and had more. Marvin and Lonny were busy teaching and preaching. Herman attended all the lessons. He worked very hard at fixing himself so he’d be a Good Lemming. He repeated the stories over and over again. He repeated the Lemming Mantra extra times every day.&lt;br /&gt;&lt;br /&gt;But Herman loved going to the park and watching the clouds. Every day it was different. Every minute even.&lt;br /&gt;&lt;br /&gt;He marked Big Cliff Day on his calender and as it approached, he worked extra hard at thinking Lemming Thoughts. He Felt the Sorrow. He Felt the Doom. He was a Lemming. He knew what had happened last year – he just hadn’t taken it seriously enough. Hadn’t filled his mind with Lemming Thoughts. He hadn’t repeated Over and Over again what a Lemming did and how a Lemming Thought and how Inevitable everything was.&lt;br /&gt;&lt;br /&gt;Lemming’s can’t Change! It’s how they’re Built. It’s Innate. It’s Inevitable. It’s who we Are. It’s Lemmingness!!!!&lt;br /&gt;&lt;br /&gt;The night before the Big Cliff Run, Herman worked extra hard at remembering. He laid out his special shoes and everything. Then he went to bed.&lt;br /&gt;&lt;br /&gt;The next morning was a beautiful day. Herman woke up earlier than usual. Earlier than everybody else, in fact. Since he was early, he decided to go to the Park One Last Time. So he did.&lt;br /&gt;&lt;br /&gt;It was so nice. The clouds were making beautiful swirls. It was almost hypnotic. Lovely. Beautiful. Peaceful. Happy.&lt;br /&gt;&lt;br /&gt;Herman woke up suddenly.&lt;br /&gt;&lt;br /&gt;He remembered – that he’d forgotten again.&lt;br /&gt;&lt;br /&gt;He went home.&lt;br /&gt;&lt;br /&gt;Everyone was gone and he was alone again.&lt;br /&gt;&lt;br /&gt;This time, Herman sat down and shook his head.&lt;br /&gt;&lt;br /&gt;“Something isn’t right,” he thought. He started to go to Marvin, but then stopped. He had an idea – well maybe just the start of one.&lt;br /&gt;&lt;br /&gt;Could Marvin be wrong? No!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Idea&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Herman thought and thought and thought and thought and then fell asleep. Thinking is tough work and he wasn’t used to it. All his life Herman hadn’t actually ‘thought’. He’d been a Good Lemming and he’d only repeated what he was told. He’d been told Over and Over what to repeat, so he did it. He repeated the Lemming Mantra. He repeated the Song of Sorrows. He repeated the Five Reasons for Melancholy. He kept the Record of His Life in a little book – where he wrote down Every Bad Thing. He read the book from cover to cover every week (it took longer and longer the more he wrote into it – in fact it was getting to where he didn’t have time to do much else)&lt;br /&gt;&lt;br /&gt;Herman did his duty and met with the Other Lemmings. They all took turns telling about the Bad Things, reminding each other how terrible life was. Over and over. And when one of them saw something nice and beautiful, they made doubly sure that everyone took a turn telling what was bad about the Nice Thing and how disappointing it would be. They were very, very good at protecting each other against the Unbearable Pain of False Hope.&lt;br /&gt;&lt;br /&gt;But as the year wore on, Herman noticed how much work it was to remember to feel bad. He was tired all the time. He didn’t go to the Park as much.&lt;br /&gt;&lt;br /&gt;After a while, he found himself just sitting in his chair looking out the window. Not repeating the Mantra. Not reading the Bad Things book. Just sitting and looking.&lt;br /&gt;&lt;br /&gt;That’s when he started really thinking.&lt;br /&gt;&lt;br /&gt;What if . . . what if . . . what If . . . WHAT IF LIFE REALLY WASN’T SO BAD?&lt;br /&gt;&lt;br /&gt;He used to like going to the park. It was fun. It was fun because he wasn’t Thinking the Bad Thoughts. He wasn’t Remembering the Sorrow.&lt;br /&gt;&lt;br /&gt;He had the Thought!&lt;br /&gt;&lt;br /&gt;“Maybe thinking the Sorrow Makes the Sorrow.”&lt;br /&gt;&lt;br /&gt;And then the Discovery.&lt;br /&gt;&lt;br /&gt;“Maybe if I don’t think it all the time, it will Go Away”&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Interlude (again)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Herman didn’t know what to do. He’d never had a thought on his own before. He worried and worried that it was Wrong. Marvin Thought and Marvin Taught. Lonny will be the new Thinker and Teacher – once he’s ready. “I’m not Smart enough,” thought Herman.&lt;br /&gt;&lt;br /&gt;But the Thought wouldn’t go away. It kept coming back.&lt;br /&gt;&lt;br /&gt;It was strange because Herman didn’t have to work at thinking this thought. It just kept coming back. Not always the same and not very clear. It was more like a feeling that said “It doesn’t have to be this way” and “That’s a nice thing, let’s think about it for a while”.&lt;br /&gt;&lt;br /&gt;It wasn’t so much the Things he was Thinking about, but how the Thoughts felt. Like the nice fluffy clouds and the warm sun. Nice and peaceful. Calm and serene. Not at all strong and hurting – like he was supposed to think.&lt;br /&gt;&lt;br /&gt;Herman finally decided he needed to see Marvin.&lt;br /&gt;&lt;br /&gt;So he went.&lt;br /&gt;&lt;br /&gt;Marvin was even more displeased. He barked and preached at Herman for over two whole hours. He wouldn’t answer any of Herman’s questions - in fact he just ignored them. Then he told Herman to Go Home, Believe, and Behave.&lt;br /&gt;&lt;br /&gt;As he trudged home, he say Lonny dragging another bag of Cheetos up the hill to Marvin. Lonny was tired, so he was happy to stop and talk. Herman told him everything he’d tried to tell Marvin. He finished up with “I just don’t understand. I just don’t understand. I just ,” at which point Lonny interrupted him.&lt;br /&gt;&lt;br /&gt;“Look, Herman,” he said, “I like you, even though you’ve got some screwy ideas and I wish I could help you. Marvin’s getting kind of old and he just doesn’t have the patience he used to have. But I don’t have the time right now – but if you’d like to borrow my Book, I’ll let you have it for a bit. I’ve got to have it back on Tuesday, but maybe it will help.”&lt;br /&gt;&lt;br /&gt;A book? Herman had never heard of the Book before. He knew how to read and write – like all good Lemmings, but he didn’t know there was a Book. He thought Marvin had learned the Stories from his Teacher and his Teacher from his Teacher and like that.&lt;br /&gt;&lt;br /&gt;Lonny was holding out the Book, so Herman took it, mumbling something to cover his embarrassment, and scuttled home.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Book&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When Herman got home, he opened the Book and started to read. It made his head hurt because it didn’t make sense.&lt;br /&gt;&lt;br /&gt;“I’ll never understand this by Tuesday,” he thought, so he decided to make his own copy. He got to work, copying the Book.&lt;br /&gt;&lt;br /&gt;After that, Herman spent every day reading his copy of the Book. He kept looking for what Marvin had Taught him, but it never really seemed to fit.&lt;br /&gt;&lt;br /&gt;He read “Our Thoughts make our World, so Choose your Thoughts Carefully” and he remembered how Marvin had droned over and over what thoughts to think. But it just didn’t feel right because the book said, “The Thoughts you hold Dear will Be your Life – so Think Thoughts of Peace and Joy”.&lt;br /&gt;&lt;br /&gt;He read and read and thought and thought and became more and more confused. He thought of going to the Great Marvin, but that frightened him. Then he thought of Lonny. Maybe he could explain it.&lt;br /&gt;&lt;br /&gt;So, the next day he waited for Lonny to come by on his daily quest for Cheetos for the Great Marvin.&lt;br /&gt;&lt;br /&gt;“Excuse me Lonny, I have some questions about the Book”&lt;br /&gt;&lt;br /&gt;Lonny stopped and looked puzzled – or maybe was shocked and stopped so he wouldn’t fall down.&lt;br /&gt;&lt;br /&gt;“What Book?” he asked.&lt;br /&gt;&lt;br /&gt;“The one you lent me and I copied,” Herman replied.&lt;br /&gt;&lt;br /&gt;“The one you copied?” asked Lonny. “That’s impossible. There is only one Book. There can’t be two – it’s Forbidden.”&lt;br /&gt;&lt;br /&gt;Startled, Herman looked confused. “But I had to copy it so I could get it back to you on Tuesday. I couldn’t understand it that fast.”&lt;br /&gt;&lt;br /&gt;Lonny looked worried. “Please don’t tell anyone.” (meaning Marvin) “Please don’t, tell me you won’t.”&lt;br /&gt;&lt;br /&gt;“Sure,” said Herman. “But will you help me?”&lt;br /&gt;&lt;br /&gt;“With what?”&lt;br /&gt;&lt;br /&gt;“Well, I know what I was taught and I know what the Book says and they’re not the same,” Herman began.&lt;br /&gt;&lt;br /&gt;“Oh yes they Are!!!” Lonny said. “You just don’t Understand. That’s why there’s only One Book. You have to Taught How to Read It.”&lt;br /&gt;&lt;br /&gt;“Will you teach me?” Herman asked.&lt;br /&gt;&lt;br /&gt;“I can’t. You’re not the Student – I am,” Lonny said. “I can’t Teach until I’m the Master and the I can Only Teach the Student. That’s how it is.”&lt;br /&gt;&lt;br /&gt;“Well, the Book says that the Master taught his students,” Herman began.&lt;br /&gt;&lt;br /&gt;“That’s Right,” said Lonny, “and that’s why there can only be One Student and No One can Teach except the Master.”&lt;br /&gt;&lt;br /&gt;“But, it says in the Book that the Master taught lots of students - not all of them learned well, of course, but he taught everyone. I don’t understand.”&lt;br /&gt;&lt;br /&gt;“That’s right, you don’t. You see, the Master could only really Teach the Students who learned, not the other students. And those other students went around teaching others Wrong Things.”&lt;br /&gt;&lt;br /&gt;Herman scratched behind his left ear. “Hmm. So now the Master doesn’t let anybody else Teach or read the Book because they might get it Wrong?”&lt;br /&gt;&lt;br /&gt;“That’s Right,” Lonny replied.&lt;br /&gt;&lt;br /&gt;“And Marvin knows How to Read the Book because . . .” Herman trailed off, confused.&lt;br /&gt;&lt;br /&gt;Lonny sighed and sat down. “Look,” he said, “Marvin’s Master Taught him and he had a Master who Taught Him and so on – all the way back to the Master who Wrote the Book. That’s how Marvin knows how to Read it and How I’m Learning too.” Lonny looked compassionately on Herman. “You’ll just never understand.”&lt;br /&gt;&lt;br /&gt;“Will you help me?”&lt;br /&gt;&lt;br /&gt;“I’m sorry, but I can’t,” Lonny answered.&lt;br /&gt;&lt;br /&gt;“Well, how about just one question then,” Herman asked.&lt;br /&gt;&lt;br /&gt;“OK. Sure. But, just one.”&lt;br /&gt;&lt;br /&gt;“Marvin teaches us to remember the Bad things, to Write them Down in our book of bad things and to read it every week. And anytime someone thinks that Bad won’t happen, it’s our Duty to remind them of All the Bad things. The Book says that what we Think is our World. Doesn’t that make our World Bad instead of Good?”&lt;br /&gt;&lt;br /&gt;Lonny sighed. “See, you just don’t understand. What’s the worst thing that can happen to you?”&lt;br /&gt;&lt;br /&gt;“I really don’t know,” Herman said.&lt;br /&gt;&lt;br /&gt;“Think about this: suppose you thought you would get a great big Strawberry Shortcake for dinner tomorrow. You’d spend the whole day and night just thinking about how great that would be. You’d plan the whole next day how good it would taste and comfy and fat your belly would be. Can you imagine that?”&lt;br /&gt;&lt;br /&gt;“Oh boy, yeah. I can almost taste it now.” Herman started to drool.&lt;br /&gt;&lt;br /&gt;“Ok,” Lonny continued, “now think about how disappointed you’ll be when you don’t get it or if it’s filled with ants or the Strawberries are rotten. Think about that.”&lt;br /&gt;&lt;br /&gt;“Yech! That’s terrible,” Herman responded. His fur actually started to wilt.&lt;br /&gt;&lt;br /&gt;“So you see,” Lonny lectured, “it’s much, much better to never get your hopes up because that makes it so much farther to fall down. You see thinking Bad Thoughts protects use from disappointments like that – and even worse.”&lt;br /&gt;&lt;br /&gt;“That’s why thinking Bad thoughts is Really Good,” Lonny finished. “I hope that helps. Do you see why someone has to Teach you How to Read the Book? And why it’s not Good for You?”&lt;br /&gt;&lt;br /&gt;Herman just mumbled.&lt;br /&gt;&lt;br /&gt;“Well, I hope that helps you – but I have to go about my duties,” Lonny said, standing up and starting to walk away. Then he stopped, “and remember, please don’t tell any anybody.”&lt;br /&gt;&lt;br /&gt;Herman started. “Oh, sorry. Yeah, thanks. No, I won’t tell anyone. Bye”&lt;br /&gt;&lt;br /&gt;So, Lonny went off to do his important tasks and Herman sat and sat some more. And thought and thought some more. What Lonny said made some sense, but something just didn’t seem right.&lt;br /&gt;&lt;br /&gt;Herman went on like this for a long time. Reading the Book and thinking about what he had been Taught and what Lonny had said. His fur got dull.&lt;br /&gt;&lt;br /&gt;One night, very very late, Herman snapped. “I’ll never make sense of it,” he said out loud.&lt;br /&gt;&lt;br /&gt;From that night on, Herman quit trying to be a good Lemming. He stopped doing what he’d been Taught. He forgot about the Book. He’d decided to just live the best he could.&lt;br /&gt;&lt;br /&gt;Herman no longer wrote in the book of Bad Things. He no longer recited the Lemming Mantra. He began to forget the teachings. He didn’t read the Book – in fact, he forgot about it.&lt;br /&gt;&lt;br /&gt;Each day Herman went to the Park. He looked at the trees and the grass. Slowly, the Bad Thoughts didn’t come so often. They didn’t Stay so Long. He didn’t feel so bad. The Great Sorrow lifted.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Realization&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One day Herman saw the Book. Wrinkling his brow, he picked it up and opened to a page at random. It made sense. It was simple. Why hadn’t he understood it before? You really are what you Think. And you can Chose what you Think.&lt;br /&gt;&lt;br /&gt;Lonny was Wrong. Marvin was Wrong. Thinking Bad Thoughts didn’t Protect you, it made a Bad World. If the Strawberries are rotten, then just forget about it: there will be fresh ones some day.&lt;br /&gt;&lt;br /&gt;The Answer is to Forget about the Bad and Think about the Good!&lt;br /&gt;&lt;br /&gt;Herman couldn’t wait to tell everyone.&lt;br /&gt;&lt;br /&gt;He ran outside.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The End&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Well, I won’t tell about how everyone laughed at him. How no one believed. How Marvin was even More than Displeased (luckily he was too fat to move or he might have squashed Herman flat). Or Lonny’s look of pity.&lt;br /&gt;&lt;br /&gt;Nobody believed him. After all, the were Lemmings and he was only a lemming – not a Real Lemming At All. He didn’t understand the Burden that came with Lemmingness – the Great Sorrow – the Inevitability of the Great and Senseless Death, crushed at the bottom of the Big Cliff. He didn’t understand.&lt;br /&gt;&lt;br /&gt;On Big Cliff Day, Herman walked out to the side of the road and shouted to them as they ran by: “You don’t have to go! Just go to the Park! Just Forget the Bad Stuff! You have a Choice!”.&lt;br /&gt;&lt;br /&gt;The ones who heard him clapped their front paws over their ears so they couldn’t hear – which made it very hard to run with their noses in the dirt. But they didn’t care. They wrapped their misery around themselves proudly and – bleeding and with broken teeth – plowed on toward the cliff.&lt;br /&gt;&lt;br /&gt;All the while, Marvin sat on his hill – praising their Lemmingness, while he ate his (final) bag of Cheetos. He would not live to see another Big Cliff Day. It was now Lonny’s turn to be the Master.&lt;br /&gt;&lt;br /&gt;It slowly dawned on Herman that they would defend their misery with their last dying breath rather than change their minds. “They think they are Lemmings,” he said, softly, under his breath, “They think that if they change their minds about something, they won’t be themselves.”&lt;br /&gt;&lt;br /&gt;So, Herman walked to the Park and watched the day go by.&lt;br /&gt;&lt;br /&gt;He was sad.&lt;br /&gt;&lt;br /&gt;Then he realized that, while he now knew, he couldn’t help them. They didn’t want a better life. They wanted to feel secure in the life they already had – so they only listen to Lemmings who will tell them that they are right. Lemmings who confirm their misery. He was just a lemming.&lt;br /&gt;&lt;br /&gt;But that’s OK.&lt;br /&gt;&lt;br /&gt;So, he decided – right there – that if anybody asked, he would tell them, but that he wouldn’t bother anybody any more. (the thought of those Lemmings pushing their noses in the dirt was just too much to bear, even though it was kind of funny)&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;The End&lt;/span&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/3666775354459763953-1469984825708102352?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/1469984825708102352/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=1469984825708102352' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/1469984825708102352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/1469984825708102352'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2009/07/story.html' title='A Story'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-7333663338319481387</id><published>2009-07-14T09:30:00.005-06:00</published><updated>2009-07-14T09:52:41.601-06:00</updated><title type='text'>Why XHTML is Wrong and HTML 5 is Right</title><content type='html'>I'll admit it: I fell for the XHTML hype and I've tried to convert myself to writing XHTML rather than HTML. The argument sounded good, but . . . I was wrong.&lt;br /&gt;&lt;br /&gt;Then about a month ago I read almost all of the HTML 4.01 spec - not the digestions that you find in books like &lt;span style="font-weight:bold;"&gt;Everything You Ever Wanted to Know to Be an HTML Expert!!!!! in 5 minutes a Day!!!&lt;/span&gt;. I read the real spec. I actually spent about 1/4 of my time reading the DTD.&lt;br /&gt;&lt;br /&gt;[I thought I needed to write an HTML parser in PHP - but that was just another programming hallucination which I solved in a much simpler, but vastly more limited and restrictive way]&lt;br /&gt;&lt;br /&gt;Anyway, while doing that I realized that writing an HTML parser is Hard. Whereas writing an XML parser is EASY.&lt;br /&gt;&lt;br /&gt;And that - in a succinct nutshell - is the only argument in favor of XHTML.&lt;br /&gt;&lt;br /&gt;And, along with everybody else, I blindly followed that Pundant-centric reasoning.&lt;br /&gt;&lt;br /&gt;But lets think about it: How many times do you Write an HTML Parser? For most of us, it's Zero.&lt;br /&gt;&lt;br /&gt;OK, how many times do you have to read and understand HTML? For most people it's still Zero, but for a Lot of Us it's 'All the f****ing Time!'.&lt;br /&gt;&lt;br /&gt;So - should (X?)HTML be Human Parse-able or Machine Parse-able?&lt;br /&gt;&lt;br /&gt;That is: Should (X?)HTML be Easy for Us to Read or Easy to Write simple Parsing Programs for?&lt;br /&gt;&lt;br /&gt;If you don't know the answer to that one, ... I was about to write something insulting, but that's not fair. Let's look at some history:&lt;br /&gt;&lt;br /&gt;1. RPN [that's Reverse Polish Notation]. It's easy to parse, but hard to read. It has a long history, but even the original HP calculator [showing my age] which was a commercially successful RPN calculator had to succumb and convert to algebraic notation. (and as far as I know, the only commercially successful one)&lt;br /&gt;&lt;br /&gt;2. The FORTH family of languages. Apparently this never really dies. FORTH was a stack based language which is really easy to write a parser for, but almost impossible to understand. Why? All the operations either push something on the stack or pop some stuff off, transform it and then push it back. Us Humans are NOT Stack Machines, so we can't track the state of the Stack.&lt;br /&gt;&lt;br /&gt;3. Postscript - Same problem as FORTH, but it's successful as an intermediate language to describe a rendered document. Nobody actually &lt;span style="font-style:italic;"&gt;programs&lt;/span&gt; in Postscript - we all use tools which output to Postscript and then feed that to a Postscript interpreter. [anybody every try to read that stuff?]&lt;br /&gt;&lt;br /&gt;4. Etc&lt;br /&gt;&lt;br /&gt;Point Made?&lt;br /&gt;&lt;br /&gt;But, you say, HTML Sucks!!!&lt;br /&gt;&lt;br /&gt;Right!!!&lt;br /&gt;&lt;br /&gt;Lets get behind HTML 5 and Fix it. XHTML Sucks too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-7333663338319481387?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/7333663338319481387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=7333663338319481387' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7333663338319481387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7333663338319481387'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2009/07/why-xhtml-is-wrong.html' title='Why XHTML is Wrong and HTML 5 is Right'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-2561882864904892945</id><published>2009-05-01T14:05:00.010-06:00</published><updated>2010-04-19T15:54:21.621-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>PHP, Language Design, and Confusion</title><content type='html'>References&lt;br /&gt;&lt;br /&gt;When I wrote some iterator code which returns a reference to an internal array in an object I discovered an interestingly easy to introduce bug. Without getting into the details, I left out a '&amp;' and clobbered my underlying data structure.&lt;br /&gt;&lt;br /&gt;Here's the offending loop:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;for ($row=&amp;$obj-&gt;firstRow();$row;$row=$obj-&gt;nextRow() {&lt;br /&gt;  other stuff&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;where &lt;span style="font-style:italic;"&gt;firstRow()&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;nextRow()&lt;/span&gt; are iterator methods defined on the object which do exactly what they sound like. [oh yeah, they both are defined as returning references]&lt;br /&gt;&lt;br /&gt;Spot the bug?&lt;br /&gt;&lt;br /&gt;I left off the '&amp;' between the '=' and the '$' in the update part of the &lt;span style="font-style:italic;"&gt;for&lt;/span&gt; loop. This causes &lt;span style="font-style:italic;"&gt;$obj-&gt;nextRow()&lt;/span&gt; to overwrite the &lt;span style="font-style:italic;"&gt;firstRow&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Strangely enough, if I wrote this in C I wouldn't have made the error. The equivalent C code would be:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;for (ptr=*obj-&gt;firstRow();ptr;*ptr=*obj-&gt;nextRow() {&lt;br /&gt;  *ptr-&gt; whatever&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Notice that I have to explicitly &lt;span style="font-style:italic;"&gt;dereference&lt;/span&gt; the pointer &lt;span style="font-style:italic;"&gt;ptr&lt;/span&gt; in order to clobber the initial element.&lt;br /&gt;&lt;br /&gt;So this covers PHP and the Confusion.&lt;br /&gt;&lt;br /&gt;Here's where the Language Design comes in:&lt;br /&gt;&lt;br /&gt;C makes an syntactic distinction between accessing a pointer and dereferencing it.&lt;br /&gt;&lt;br /&gt;PHP doesn't. If a variable contains a &lt;span style="font-style:italic;"&gt;reference&lt;/span&gt; then assignment deferences it &lt;span style="font-style:italic;"&gt;implicitly&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;silently&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Consequently, you can't &lt;span style="font-style:italic;"&gt;really&lt;/span&gt; understand a chunk of PHP without reading all the definitions of the variables which &lt;span style="font-style:italic;"&gt;preceed&lt;/span&gt; the chunk you're looking at. This is a bad thing and it violates that tried, true and mostly forgotten maxim of 'code locality'.&lt;br /&gt;&lt;br /&gt;This also leads to a lot of bugs - and 'Bogus' bug reports - involving references. [just check out bugs.php.net - 655 Bogus bugs relating to 'reference']&lt;br /&gt;&lt;br /&gt;I think PHP would be a lot easier to understand if there was a syntactic difference between assigning to a variable and assigning to the referrant of a variable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Practically speaking,&lt;/span&gt; I don't think it will happen because of 'backward compatibility' and 'NIH'.&lt;br /&gt;&lt;br /&gt;What I'd like to see is a dereference prefix which is accepted in PHP 5.x and becomes mandatory in PHP 6. There should also be a warning option which generates a warning if a variable containing a reference is assigned value and the variable is not prefixed.&lt;br /&gt;&lt;br /&gt;Here's my first (and only) choice:&lt;br /&gt;&lt;blockquote&gt;&amp;$foo&lt;/blockquote&gt;&lt;br /&gt;This is currently used to denote a reference when used on the right side of an assignment. It should be a simple matter to extend this to dereferencing on the left side and in expressions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-2561882864904892945?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/2561882864904892945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=2561882864904892945' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/2561882864904892945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/2561882864904892945'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2009/05/php-errors-and-how-to-make-them.html' title='PHP, Language Design, and Confusion'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-9195320353140448841</id><published>2009-04-23T22:32:00.004-06:00</published><updated>2010-04-19T15:54:21.622-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>Efficient Code - PHP</title><content type='html'>I guess I'm a nut about execution speed. Well, not if it gets in the way of clarity, but I hate writing slow code.&lt;br /&gt;&lt;br /&gt;But . . . always a 'But' . . . it's hard to know what is slow and what isn't. Seems like it should be easy, but I never know until I measure.&lt;br /&gt;&lt;br /&gt;Here's an example:&lt;br /&gt;&lt;br /&gt;The PHP manual page for &lt;span style="font-style: italic;"&gt;preg_split()&lt;/span&gt; says that you shouldn't use it unless you need the flexibility of regular expressions. You should use &lt;span style="font-style: italic;"&gt;explode()&lt;span style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; or &lt;span style="font-style: italic;"&gt;str_split()&lt;/span&gt;, because they are simpler and therefore faster. I believed that.&lt;br /&gt;&lt;br /&gt;Then I thought I'd like to see how much faster, so I wrote a couple of loops which split a comma separated string with both &lt;span style="font-style: italic;"&gt;preg_split() &lt;/span&gt;and &lt;span style="font-style: italic;"&gt;explode()&lt;/span&gt; to see how much I was really losing.&lt;br /&gt;&lt;br /&gt;Here's are the average times of 10 passes through 1,000,000 splits using each:&lt;br /&gt;preg_split() - 3.51239209175 seconds&lt;br /&gt;explode() - 4.33661820889 seconds&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;preg_split() &lt;/span&gt;is about 23% &lt;span style="font-weight: bold;"&gt;Faster&lt;/span&gt; than &lt;span style="font-style: italic;"&gt;explode&lt;span style="font-style: italic;"&gt;()&lt;/span&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;I'm still not sure I believe it. Here's the code - so you can try it yourself.&lt;br /&gt;&lt;br /&gt;And, please let me know if you see anything I did wrong.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;$str = 'this, is , a , string, with , commas, in ,it';&lt;br /&gt;$count = 1000000;&lt;br /&gt;$passes = 10;&lt;br /&gt;$times = array(xdebug_time_index());&lt;br /&gt;$avg = array('preg' =&gt; array(), 'explode' =&gt; array(), 'map-explode' =&gt; array());&lt;br /&gt;function dt($offset = 1)&lt;br /&gt;{&lt;br /&gt;  global $times;&lt;br /&gt;  $last = count($times) - 1;&lt;br /&gt;  return $times[$last] - $times[$last - $offset];&lt;br /&gt;} // end of dt()&lt;br /&gt;&lt;br /&gt;for ($pass=0;$pass&lt;$passes;$pass++) {&lt;br /&gt;  echo "Pass $pass\n";&lt;br /&gt;  $times[] = xdebug_time_index();&lt;br /&gt;  for ($i=0;$i&lt;$count;$i++) {&lt;br /&gt;    $v = preg_split('/^\s*,\s*/', $str);&lt;br /&gt;    unset($v);&lt;br /&gt;  }&lt;br /&gt;  $times[] = xdebug_time_index();&lt;br /&gt;  $avg['preg'][] = dt();&lt;br /&gt;  echo "$count preg_split's(regx, str): " . dt() . "\n";&lt;br /&gt;  &lt;br /&gt;  $times[] = xdebug_time_index();&lt;br /&gt;  for ($i=0;$i&lt;$count;$i++) {&lt;br /&gt;    $v = array_map('trim', explode(',', $str));&lt;br /&gt;    unset($v);&lt;br /&gt;  }&lt;br /&gt;  $times[] = xdebug_time_index();&lt;br /&gt;  $avg['map-explode'][] = dt();&lt;br /&gt;  echo "$count array_map(trim, explode(',', str)): " . dt() ."\n";&lt;br /&gt;&lt;br /&gt;  $times[] = xdebug_time_index();&lt;br /&gt;  for ($i=0;$i&lt;$count;$i++) {&lt;br /&gt;    $v = explode(',', $str);&lt;br /&gt;    unset($v);&lt;br /&gt;  }&lt;br /&gt;  $times[] = xdebug_time_index();&lt;br /&gt;  $avg['explode'][] = dt();&lt;br /&gt;  echo "$count explode(',', str): " . dt() ."\n";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;echo "Averges\n";&lt;br /&gt;foreach ($avg as $key =&gt; $ar) {&lt;br /&gt;  echo "$key average of $passes trials of $count splits: " . array_reduce($ar, create_function('$a,$b', 'return $a+$b;'), 0) / count($ar) . "\n";&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/3666775354459763953-9195320353140448841?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/9195320353140448841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=9195320353140448841' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/9195320353140448841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/9195320353140448841'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2009/04/efficient-code-php.html' title='Efficient Code - PHP'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-8545321303669176950</id><published>2009-04-21T22:25:00.008-06:00</published><updated>2010-04-19T15:56:39.611-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='s/w opinions'/><title type='text'>Documentation - It's Part of the Design Process</title><content type='html'>I was documenting some code I just wrote to create a packing list for an internet store we'll be opening soon. It's kind of a hairy problem to come up with a semi-optimal allocation of goods into boxes - but absolutely necessary to do right if you want to accurately estimate shipping &lt;span style="font-style: italic;"&gt;and&lt;/span&gt; keep costs down.&lt;br /&gt;&lt;br /&gt;It took me about a week to really get my head around the problem so that I could solve it. The actual solution now looks  pretty obvious - but it won't in six months or a year.&lt;br /&gt;&lt;br /&gt;So I document all my code - profusely, but compactly.&lt;br /&gt;&lt;br /&gt;A Strange Thing happened while I was writing the doc: I found and &lt;span style="font-style: italic;"&gt;corrected&lt;/span&gt; a whole bunch of bugs - both coding bugs, 'bugs of omission', and design bugs. That's when I realized that I use the very act of documenting code as part of my design iterations.&lt;br /&gt;&lt;br /&gt;So, I started thinking about what I do and why I do it the way I do - which is (as usual) a bit contrary to 'accepted best-practice'.&lt;br /&gt;&lt;br /&gt;First of all, there are basically Three Types of documentation in code:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The Code Itself&lt;/li&gt;&lt;li&gt;Comments&lt;/li&gt;&lt;li&gt;Doc&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;The Code&lt;/span&gt;: My code is semi-self documenting. I do the usual stuff: identifiers are semantically related to their use [function save_data() - etc]; use of white space; consistent breaking of long lines and breaks at binary operators; consistent indentation.&lt;br /&gt;&lt;br /&gt;But you can do more.&lt;br /&gt;&lt;br /&gt;Simple, direct, and consistent code does wonders for readability. Consistency in within-loop logic [use if elseif elseif ... or switch case case default or if () { stuff; continue;} if () { stuff; continue;}]. I don't think it matters what style you use as much as consistency and simplicity.&lt;br /&gt;&lt;br /&gt;Small is usually good as well. We used to talk about 'locality of code' meaning that our code was written in chunks which weren't 'too long.' 'Too long' usually really meant 'it fits in the window of my editor' so that you can stare at it and understand the whole thing. There's also 'too short', but the Ruby on Rails guys have the market on that with their obsessive DRYness.&lt;br /&gt;&lt;br /&gt;Anyway, the Code itself is always the final authority on what the program does - so it's the most authoritative documentation.&lt;br /&gt;&lt;br /&gt;Do yourself a favor and make it as readable as possible - you might have to fix it later.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Comments&lt;/span&gt;: Helpful hints which make the Code more readable. Some (IMHO) IDIOT came up with the idea that Comments Must be Set Off with Big Boxes of Stars or something like that.&lt;br /&gt;&lt;br /&gt;Why?&lt;br /&gt;&lt;br /&gt;Well, I'll tell you.&lt;br /&gt;&lt;br /&gt;We used to write programs on Paper and then punch them into Punch Cards and run them through a Card Reader and then get a Big Wide Printout on Greenbar paper and do our debugging at a desk. We'd page through this Paper with a pencil and write revisions to our programs. The paper was 14 inches wide [132 columns] and 11 inches long [60 lines at 6 lines per inch with 1/2 inch top and bottom margins].&lt;br /&gt;&lt;br /&gt;In those days it made sense to Mark Off the comment blocks. It made them easy to spot - both for someone reading the code and for the Boss as he walked by your desk. [You'd get demerits for &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; commenting your code, so it was a good idea to make it easy for him to see].&lt;br /&gt;&lt;br /&gt;Things have changed. You can easily flip around in an on-screen editor, but you can't very well write on it. It works a lot better if the information in the editor window is very &lt;span style="font-style: italic;"&gt;dense&lt;/span&gt;. The way to do that is to write meaningful comments with as little &lt;span style="font-style: italic;"&gt;excess&lt;/span&gt; white space as possible.&lt;br /&gt;&lt;br /&gt;Now I use blank lines to separate logically disjoint chunks of code and preceed them with comments - if appropriate - but I don't waste a lot of screen space blocking off comments.&lt;br /&gt;&lt;br /&gt;I think we need a very high Signal to Noise ratio - and big blocks of comment markers are just noise.&lt;br /&gt;&lt;br /&gt;I don't use PHPDoc because those guys seem to think that the Documentation and the Comments are More Important than the Code itself. I don't. I want as much Code on the screen as I can get &lt;span style="font-style: italic;"&gt;if it is blocked out so that the logic is obvious and commented as needed.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Doc&lt;/span&gt;: The Doc is narative description of what the code does, how it does it, how to use it, calling parameters, etc etc. Can't live without it.&lt;br /&gt;&lt;br /&gt;I've experimented with all kinds of methods. I used to write UNIX style man pages - and they are still a really good format. But now days, everything has to be in HTML, so I've changed.&lt;br /&gt;&lt;br /&gt;There are a lot of Documentation Project things - like PHPDoc - but I don't use them.&lt;br /&gt;&lt;br /&gt;I think they're too complex &lt;span style="font-style: italic;"&gt;and&lt;/span&gt; they are usually specific to one language. Besides, they just aren't necessary for good, clear documentation.&lt;br /&gt;&lt;br /&gt;Like many people, I work in several languages [one reason I'm bald] so I need a multi-lingual documentation system. I also want something which doesn't take up a lot of space in my program files and which is really simple. Here are my 'Must Haves':&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Must allow the Doc to be imbeded in the same file with the code&lt;/li&gt;&lt;li&gt;Must produce HTML&lt;/li&gt;&lt;li&gt;Must be flexible&lt;/li&gt;&lt;li&gt;Must be very Simple&lt;/li&gt;&lt;/ul&gt;I couldn't find anything which didn't take multiple days [or weeks] to learn, so I wrote up something to pull Textile makeup out of a simple text file and that's what I use.&lt;br /&gt;&lt;br /&gt;Frankly, I'm smart enough and write well enough to describe what some code does. &lt;span style="font-style: italic;"&gt;So are you&lt;/span&gt;. Just pretend you're writing for yourself about a year from now when you have to find a bug and fix it in record time - or you'll be fired.&lt;br /&gt;&lt;br /&gt;What kind of Doc do you want then? Clear, correct, self-contained without a lot of references jumping around, etc etc. Write something which will save your butt when the crunch comes and you're fine.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Design?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So what does this have to do with Design?&lt;br /&gt;&lt;br /&gt;As I write my Doc - part 3 of the Code Documentation - I find myself thinking about how the whole thing works and how understandable it is. It can get kind of contemplative.&lt;br /&gt;&lt;br /&gt;Another thing which happens is that I find myself wondering why in the hell I wrote something and what it really does - so I go through the logic again.&lt;br /&gt;&lt;br /&gt;There's a different perspective and attitude when reading code to understand and clearly document it than there is when writing it initially. At least there should be.&lt;br /&gt;&lt;br /&gt;When I write code, I get involved in the microscopic detail, in solving the problem, in creating the logic and the loops.&lt;br /&gt;&lt;br /&gt;When I read code to document it, I get involved in the overall strategy of the solution and the clarity of the logic. It's just different.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Anyway, that's how I think about Documenting code now days.&lt;br /&gt;&lt;br /&gt;Oh, if you're interested in my document extractor - I'm planning on dumping on the download page of http://www.clove.com. It's written in Python, so it should run about anyplace.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-8545321303669176950?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/8545321303669176950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=8545321303669176950' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8545321303669176950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8545321303669176950'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2009/04/documentation-its-part-of-design.html' title='Documentation - It&apos;s Part of the Design Process'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-991226599160782324</id><published>2009-03-03T09:22:00.004-07:00</published><updated>2010-04-23T10:41:00.953-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='W3'/><category scheme='http://www.blogger.com/atom/ns#' term='XMP'/><title type='text'>How can you screw up XML? Part II</title><content type='html'>XML is overly wordy. It has lots of required text.&lt;br /&gt;&lt;br /&gt;I think the theory is - if there really is one - that longer words make the computer-code more easily understood. That was certainly true when we were using FORTRAN with 6 character variable names and Basic with 2 characters - but there's a limit. That limit is probably around 32 characters - 1/3 of a screen line - at which point you need some white space and punctuation.&lt;br /&gt;&lt;br /&gt;XML doesn't provide for white space, just punctuation. As (semi-)intelligent creatures, we need white space to clump symbols into recognizable things. It seems to be how we parse. Computers don't distinguish, so . . . They can read XML, but we can't. [maybe it's really a plot by the machines and W3 are a bunch of Cylons?]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So maybe the extra stuff is supposed to make XML more reliable? To get there, we have to talk about two slightly different subjects: Bandwidth and Information Theory.&lt;br /&gt;&lt;br /&gt;Bandwidth measures how fast we can transmit messages. The bigger the bandwidth, the faster the electronic wiggles are and so the more Bits we can represent in a given chunk of time - say a second. Big Bandwidth is Good.&lt;br /&gt;&lt;br /&gt;Effective Bandwidth is the fraction of the real Bandwidth you get to use for your stuff - the content you want to see, transmit, or use - read streaming video from hulu.com. The more non-Content characters in the Protocol [read XML] used to encode your 'stuff', the lower your Effective Bandwidth. [You pay for Real Bandwidth, but you Get Effective Bandwidth - it's kind of like sales tax or Net Income after Income Tax]&lt;br /&gt;&lt;br /&gt;Information Theory studies how to transmit Information in the presence of Noise. It turns out that you can always get your message across accurately - most of the time - if you use a fancy enough code. A Code takes a simple message and adds a lot of extra bits which allow the receiver to tell if the message was messed up [received a 0 where there should have been a 1] and to reconstruct it. When you have more noise, you have to add more reconstruction bits. That makes the message longer. So Information Theory says - if you want reliable communication, you have to allocate some of your Bandwidth to these reconstruction bits - called Redundancy - so that your Effective Bandwidth is lower than your actual Bandwidth.&lt;br /&gt;&lt;br /&gt;Now let's apply this to XML.&lt;br /&gt;&lt;br /&gt;XML adds extra stuff to create a rigid structure for you message. This has Nothing to do with Information Theory because XML is transferred over TCP - which is a Lossless Protocol - meaning that, if the message gets there At All, it's guaranteed to be OK. There's No Noise on TCP. [The TCP protocol has already eaten up the Bandwidth required by Information Theory to get your 'stuff' to you]&lt;br /&gt;&lt;br /&gt;The XML extra stuff is there so computer programs can easily parse the message and use it's Content once it gets there.&lt;br /&gt;&lt;br /&gt;XML's 'extra stuff' shares the Same Bandwidth as the Content inside the XML message.&lt;br /&gt;&lt;br /&gt;I ask you: what's more important: the Content or the 'extra stuff'?&lt;br /&gt;&lt;br /&gt;Personally, I think the 'extra stuff' should be as small and efficient as possible so we can use as much of the Bandwidth for Content.&lt;br /&gt;&lt;br /&gt;W3 must think that the 'extra stuff' is more important than content because they make their protocols as bulky as they can.&lt;br /&gt;&lt;br /&gt;Don't believe me? go to &lt;a href="http://www.w3.org/"&gt;www.w3.org&lt;/a&gt; and read some of their specs - try name spaces or the RDF spec or just about anything. All Structure with minimal space for Content.&lt;br /&gt;&lt;br /&gt;Why do we put up with this?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-991226599160782324?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/991226599160782324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=991226599160782324' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/991226599160782324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/991226599160782324'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2009/03/how-can-you-screw-up-xml-part-ii.html' title='How can you screw up XML? Part II'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-7167351467916558186</id><published>2009-03-03T08:13:00.010-07:00</published><updated>2009-03-03T09:18:14.524-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JSON'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='W3'/><category scheme='http://www.blogger.com/atom/ns#' term='XMP'/><title type='text'>How can you screw up XML?</title><content type='html'>&lt;p&gt;XML is about the simplest thing around. How can you screw it up?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I'm writing some metadata-extraction-from-image code and started looking at Adobe's XMP.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;XMP is written using the W3's RDF spec - [almost wrote RDF framework, but that would then be Resource Description Framework framework (RDF&lt;sup&gt;2&lt;/sup&gt;), which might not be the same thing].&lt;br /&gt;&lt;/p&gt;&lt;p&gt;RDF defines a 'Framework' for writing machine parseable statements of the form:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;b&gt;Tim&lt;/b&gt; &lt;i&gt;has&lt;/i&gt; a &lt;b&gt;bike&lt;/b&gt;.&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;RDF calls:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Tim&lt;/b&gt; the &lt;i&gt;subject&lt;/i&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;has&lt;/b&gt; the &lt;i&gt;predicate&lt;/i&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;bike&lt;/b&gt; the &lt;i&gt;object&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;It &lt;i&gt;makes&lt;/i&gt; you write URI's for both the subject and predicate - and have translation syntax between real words and the URI's.&lt;br /&gt;&lt;br /&gt;Here's an example from the RDF Primer. It says: 'http://www.example.org was created on August 16, 1999'&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;blockquote&gt;&lt;code&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&lt;br /&gt;           xmlns:exterms="http://www.example.org/terms/"&amp;gt;&lt;br /&gt; &amp;lt;rdf:Description rdf:about="http://www.example.org/index.html"&amp;gt;&lt;br /&gt;     &amp;lt;exterms:creation-date&amp;gt;August 16, 1999&amp;lt;/exterms:creation-date&amp;gt;&lt;br /&gt; &amp;lt;/rdf:Description&amp;gt;&lt;br /&gt;&amp;lt;/rdf:RDF&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;/pre&gt;The RDF is 5.9 times LONGER than the English Language Sentence. That's an increase&lt;br /&gt;in text of about 83%. Or, to put it another way, a BANDWIDTH UTILIZATION of about 17%.&lt;br /&gt;&lt;br /&gt;For What Gain?&lt;br /&gt;&lt;br /&gt;Nothing. And it takes them 6 LONG RFC style documents to define this messs.  That's 6 Long, Boring documents with much repetition and pedantic phrasing with many MUST's and SHALL's and MAY's.&lt;br /&gt;&lt;br /&gt;But it can be parsed by a machine - if you can understand the spec well enough to write the code.&lt;br /&gt;&lt;br /&gt;Why take something so simple and make it so incomprehensibly complex?&lt;br /&gt;&lt;br /&gt;But - Believe it Not - I digress.&lt;br /&gt;&lt;br /&gt;XMP is written using RDF [why re-invent the wheel when you can use somebody else's debacle and make it worse].&lt;br /&gt;&lt;br /&gt;I'm not going to get into XMP - but at first glance it looks like they're using attributes for data, XML entities for data, and RDF nested structures for data - with NO obvious logic as to when and where these choices are made. To further mess it up, everything uses XPATH name spaces - which my XML parser translates back to URI's [which point to nothing, but are long and look cool], like a 'good parser should' - which obfuscates the already obfuscated and bulks out the fluff to content ratio admirably.&lt;br /&gt;&lt;br /&gt;Yech!!!!!!!&lt;br /&gt;&lt;br /&gt;Here's how I think XML &lt;i&gt;intended&lt;/i&gt; to encapsulate a website's creation date:&lt;br /&gt;&lt;pre&gt;&lt;blockquote&gt;&amp;lt;site-info site_name="www.example.com"&amp;gt;&lt;br /&gt;&amp;lt;creation-date&amp;gt;August 16, 1999&amp;lt;/creation-date&amp;gt;&lt;br /&gt;&amp;lt;/site-info&amp;gt;&lt;/blockquote&gt;&lt;/pre&gt;It's machine parse-able. It's (almost) human readable. It only wastes 50% of the bandwidth - as opposed to 85% using RDF.&lt;br /&gt;&lt;br /&gt;How about &lt;a href="http://www.json.org/"&gt;JSON&lt;/a&gt; - where the entire spec fits on one web page:&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;blockquote&gt;{&lt;br /&gt; "site_info": {&lt;br /&gt;   "site": "www.example.org",&lt;br /&gt;   "creation_date": "August 16, 1999"&lt;br /&gt; }&lt;br /&gt;}&lt;/blockquote&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-7167351467916558186?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/7167351467916558186/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=7167351467916558186' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7167351467916558186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7167351467916558186'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2009/03/how-can-you-screw-up-xml.html' title='How can you screw up XML?'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-5663841807506845621</id><published>2009-02-17T10:17:00.009-07:00</published><updated>2009-02-17T13:02:47.443-07:00</updated><title type='text'>PHP Input Cleaning</title><content type='html'>I've been buried in my be-all, end-all, does-everything CMS / e-commerce site.&lt;br /&gt;I thought I'd come up for err (or air) and here's what happened.&lt;br /&gt;&lt;br /&gt;Below is an object which does lazy input cleaning of GET and POST data.&lt;br /&gt;&lt;br /&gt;You use it by creating a new object [surprise].&lt;br /&gt;&lt;br /&gt;You access cleaned data as attributes of an object instance.&lt;br /&gt;&lt;br /&gt;All the cleaned data is cached in a class variable, so you can either pass around&lt;br /&gt;a global or create a bunch of instances and everything will work - within the same&lt;br /&gt;instance of the PHP program, of course. Once the Object&lt;br /&gt;is required, it acts kind of like a Singleton Pattern.&lt;br /&gt;&lt;br /&gt;You can restrict the query sources to GET, POST or REQUEST and control how it&lt;br /&gt;reacts to undefined query parameters.&lt;br /&gt;&lt;br /&gt;The documentation is in a comment at the top in Textile.&lt;br /&gt;&lt;br /&gt;In some ways, I think this is kind of neat, but on the other hand it's&lt;br /&gt;really depressing how much effort goes into something with such a simple&lt;br /&gt;objective. Seems like there should be an easier way.&lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?php&lt;br /&gt;/*&lt;br /&gt;#doc-start&lt;br /&gt;h1.  RequestCleaner&lt;br /&gt;&lt;br /&gt;Created by  on 2009-02-14.&lt;br /&gt;Copyright (c) 2009 Clove Technologies, Inc. All rights reserved.&lt;br /&gt;&lt;br /&gt;h3. Usage&lt;br /&gt;&lt;br /&gt;Create a new request cleaner:&lt;br /&gt;&lt;br /&gt;$rc = new RequestCleaner(sources, use_modes, error_mode) - where:&lt;br /&gt;&lt;br /&gt;* sources is a comma separated string OR an array with one or more of: GET, POST, REQUEST&lt;br /&gt;* use_modes is the bitwise OR of&lt;br /&gt;** RequestCleaner::USE_HTMLENTITIES - process each parameter with _htmlentities()_&lt;br /&gt;** RequestCleaner::USE_HTMLSPECIALCHARS - process each parameter with _htmlspecialchars()_&lt;br /&gt;** RequestCleaner::USE_NL2BR - process each parameter with _nl2br()_&lt;br /&gt;* error_mode - determines how the beast responds to errors - such as non-existing query parameters.&lt;br /&gt;Use one of:&lt;br /&gt;** RequestCleaner::RETURN_NULL - returns NULL&lt;br /&gt;** RequestCleaner::RETURN_FALSE - returns FALSE - can be distinguished from NULL by '===' and '!=='&lt;br /&gt;** RequestCleaner::THROW_EXCEPTION - throws an exception&lt;br /&gt;&lt;br /&gt;For example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$rc = new RequestCleaner('POST', RequestCleaner::USE_HTMLENTITIES | RequestCleaner::USE_NL2BR,&lt;br /&gt;  RequestCleaner::THROW_EXCEPTION);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To get a 'cleaned' query parameter, use '$rc-&gt;parm', where _parm_ is the parameter name.&lt;br /&gt;For example, if 'foo' is a POST parameter, then '$rc-&gt;foo' will return the value of 'foo'&lt;br /&gt;from after running the 'cleaning' routines on it.&lt;br /&gt;&lt;br /&gt;h3. Fine points&lt;br /&gt;&lt;br /&gt;All Cleaned data is cached in a RequestCleaner Class Variable, as are the sources, use and error&lt;br /&gt;modes. This means that a top level PHP program can set up the method of cleaning and&lt;br /&gt;allowed sources and all included code which uses _any_ instance of a RequestCleaner&lt;br /&gt;will use the same methods and cache.&lt;br /&gt;&lt;br /&gt;Consequently, you can either create a RequestCleaner instance at top level OR in any included or&lt;br /&gt;required file which needs to access query parameters. It doesn't matter.&lt;br /&gt;&lt;br /&gt;Attempts to access undefined attributes generate an error - as specified by _error_mode_.&lt;br /&gt;&lt;br /&gt;Query parameters which return arrays - as in &amp;lt;input type=... name="foo[]" ...&amp;gt; -&lt;br /&gt;are turned into arrays of cleaned strings which can be processed using normal loops&lt;br /&gt;and array_...() functions&lt;br /&gt;&lt;br /&gt;#end-doc&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* RequestCleaner(sources = NULL) - where sources defines a comma separated list of Super Globals&lt;br /&gt;* for attribute values. Legal names are: POST, GET, and REQUEST&lt;br /&gt;*/&lt;br /&gt;class RequestCleaner&lt;br /&gt;{&lt;br /&gt;  const ERROR_MODE_MASK = 3;&lt;br /&gt;  const RETURN_NULL = 1;&lt;br /&gt;  const RETURN_FALSE = 2;&lt;br /&gt;  const THROW_EXCEPTION = 3;&lt;br /&gt;  const NORMAL = RequestCleaner::RETURN_NULL;&lt;br /&gt;&lt;br /&gt;  const CLEANER_MODE_MASK = 0x07; // IMPORTANT: Change This as you ADD USE_modes&lt;br /&gt;  const USE_HTMLENTITIES = 1;&lt;br /&gt;  const USE_HTMLSPECIALCHARS = 2;&lt;br /&gt;  const USE_NL2BR = 4;&lt;br /&gt;  private static $use_modes = array(&lt;br /&gt;    RequestCleaner::USE_HTMLENTITIES =&gt; 'htmlentities()',&lt;br /&gt;    RequestCleaner::USE_HTMLSPECIALCHARS =&gt; 'htmlspecialchars()',&lt;br /&gt;    RequestCleaner::USE_NL2BR =&gt; 'nl2br()',&lt;br /&gt;    );&lt;br /&gt;  private static $error_modes = array(&lt;br /&gt;    RequestCleaner::RETURN_NULL =&gt; 'return NULL',&lt;br /&gt;    RequestCleaner::RETURN_FALSE =&gt; 'return FALSE',&lt;br /&gt;    RequestCleaner::THROW_EXCEPTION =&gt; 'throw Exception'&lt;br /&gt;    );&lt;br /&gt;  private static $sources = NULL;&lt;br /&gt;  private static $source_names = array();&lt;br /&gt;  private static $error_mode = NULL;&lt;br /&gt;  private static $use_mode = NULL;&lt;br /&gt;  private static $cache = array();&lt;br /&gt;  function __construct($sources = array('GET', 'POST'), $use_mode = RequestCleaner::USE_HTMLENTITIES,&lt;br /&gt;    $error_mode = RequestCleaner::RETURN_NULL)&lt;br /&gt;  {&lt;br /&gt;    if (!RequestCleaner::$sources) {&lt;br /&gt;      if ($sources) {&lt;br /&gt;        RequestCleaner::$sources = array();&lt;br /&gt;        if (is_string($sources)) {&lt;br /&gt;          $sources = preg_split("/,\s*/", trim($sources));&lt;br /&gt;        }&lt;br /&gt;        foreach ($sources as $src) {&lt;br /&gt;          RequestCleaner::$source_names[] = $src;&lt;br /&gt;          switch ($src) {&lt;br /&gt;            case 'POST':&lt;br /&gt;              RequestCleaner::$sources[] = $_POST;&lt;br /&gt;              break;&lt;br /&gt;            case 'GET':&lt;br /&gt;              RequestCleaner::$sources[] = $_GET;&lt;br /&gt;              break;&lt;br /&gt;            case 'REQUEST':&lt;br /&gt;              RequestCleaner::$sources[] = $_REQUEST;&lt;br /&gt;              break;&lt;br /&gt;            default:&lt;br /&gt;            throw new Exception("RequestCleaner::__construct($sources): Illegal Source: $tmp");&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      } else {&lt;br /&gt;        RequestCleaner::$sources = array($_POST, $_GET);&lt;br /&gt;      }&lt;br /&gt;      if (RequestCleaner::CLEANER_MODE_MASK &amp; $use_mode) {&lt;br /&gt;        RequestCleaner::$use_mode = RequestCleaner::CLEANER_MODE_MASK &amp; $use_mode;&lt;br /&gt;      }&lt;br /&gt;      if (RequestCleaner::ERROR_MODE_MASK &amp; $error_mode) {&lt;br /&gt;        RequestCleaner::$error_mode = RequestCleaner::ERROR_MODE_MASK &amp; $error_mode;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  private function stringCleaner($x)&lt;br /&gt;  {&lt;br /&gt;    if (RequestCleaner::$use_mode &amp; RequestCleaner::USE_HTMLSPECIALCHARS) {&lt;br /&gt;      $x = htmlspecialchars($x);&lt;br /&gt;    }&lt;br /&gt;    if (RequestCleaner::$use_mode &amp; RequestCleaner::USE_HTMLENTITIES) {&lt;br /&gt;      $x = htmlentities($x);&lt;br /&gt;    }&lt;br /&gt;    if (RequestCleaner::$use_mode &amp; RequestCleaner::USE_NL2BR) {&lt;br /&gt;      $x = nl2br($x);&lt;br /&gt;    }&lt;br /&gt;    return $x;&lt;br /&gt;  } // end of arrayHelper()&lt;br /&gt;  &lt;br /&gt;  private function useModesToString()&lt;br /&gt;  {&lt;br /&gt;    $ar = array();&lt;br /&gt;    foreach (array(RequestCleaner::USE_HTMLENTITIES, RequestCleaner::USE_NL2BR,&lt;br /&gt;        RequestCleaner::USE_HTMLSPECIALCHARS) as $mode) {&lt;br /&gt;      if (RequestCleaner::$use_mode &amp; $mode) {&lt;br /&gt;        $ar[] = RequestCleaner::$use_modes[$mode];&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return implode(',', $ar);&lt;br /&gt;  } // end of useModeToString()&lt;br /&gt;  &lt;br /&gt;  public function __toString()&lt;br /&gt;  {&lt;br /&gt;    return "RequestCleaner: examining " . implode(', ', RequestCleaner::$source_names)&lt;br /&gt;      . " Using " . $this-&gt;useModesToString()&lt;br /&gt;      . " / Exit Mode: " . RequestCleaner::$error_modes[RequestCleaner::$error_mode];&lt;br /&gt;  } // end of __toString()&lt;br /&gt;&lt;br /&gt;  public function __get($name)&lt;br /&gt;  {&lt;br /&gt;    if (array_key_exists($name, RequestCleaner::$cache)) {&lt;br /&gt;      return RequestCleaner::$cache[$name];&lt;br /&gt;    }&lt;br /&gt;    foreach (RequestCleaner::$sources as $source) {&lt;br /&gt;      if (array_key_exists($name, $source)) {&lt;br /&gt;        $val = $source[$name];&lt;br /&gt;        if (is_string($val)) {&lt;br /&gt;          return (RequestCleaner::$cache[$name] = RequestCleaner::stringCleaner($val));&lt;br /&gt;        } elseif (is_array($val)) {&lt;br /&gt;          return (RequestCleaner::$cache[$name] = array_map(array('RequestCleaner', 'stringCleaner'), $val));&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    switch (RequestCleaner::$error_mode) {&lt;br /&gt;      case RequestCleaner::NORMAL: return NULL;&lt;br /&gt;      case RequestCleaner::RETURN_FALSE: return FALSE;&lt;br /&gt;      case RequestCleaner::THROW_EXCEPTION:&lt;br /&gt;        throw new Exception("RequestCleaner::__get($name): Value Not Defined");&lt;br /&gt;      default:&lt;br /&gt;        throw new Exception("RequestCleaner::__get($name): ERROR: Value Not Defined / Illegal Error Mode");&lt;br /&gt;    }&lt;br /&gt;    return NULL;&lt;br /&gt;  } // end of __get()&lt;br /&gt;  &lt;br /&gt;  public function __set($name, $value)&lt;br /&gt;  {&lt;br /&gt;    switch (RequestCleaner::$error_mode) {&lt;br /&gt;      case RequestCleaner::NORMAL: return NULL;&lt;br /&gt;      case RequestCleaner::RETURN_FALSE: return FALSE;&lt;br /&gt;      case RequestCleaner::THROW_EXCEPTION:&lt;br /&gt;        throw new Exception("RequestCleaner::__set($name, $value): Setting Attributes Not Allowed");&lt;br /&gt;      default:&lt;br /&gt;        throw new Exception("RequestCleaner::__set($name, $value): Setting Attributes Not Allowed / Illegal Error Mode");&lt;br /&gt;    }&lt;br /&gt;  } // end of __set()&lt;br /&gt;  &lt;br /&gt;  public function __unset($name)&lt;br /&gt;  {&lt;br /&gt;    switch (RequestCleaner::$error_mode) {&lt;br /&gt;      case RequestCleaner::NORMAL: return NULL;&lt;br /&gt;      case RequestCleaner::RETURN_FALSE: return FALSE;&lt;br /&gt;      case RequestCleaner::THROW_EXCEPTION:&lt;br /&gt;        throw new Exception("RequestCleaner::__unset($name): Unsetting Attributes Not Allowed");&lt;br /&gt;      default:&lt;br /&gt;        throw new Exception("RequestCleaner::__unset($name): Unsetting Attributes Not Allowed / Illegal Error Mode");&lt;br /&gt;    }&lt;br /&gt;  } // end of __set()&lt;br /&gt;  &lt;br /&gt;  public function __isset($name)&lt;br /&gt;  {&lt;br /&gt;    if  (array_key_exists($name, RequestCleaner::$cache)) {&lt;br /&gt;      return TRUE;&lt;br /&gt;    }&lt;br /&gt;    foreach (RequestCleaner::$sources as $source) {&lt;br /&gt;      if (array_key_exists($name, $source)) {&lt;br /&gt;        return TRUE;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return FALSE;&lt;br /&gt;  } // end of __isset()&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// end class definitions&lt;br /&gt;&lt;br /&gt;?&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Why did I post this dramatic exposition of Programming Prowess?&lt;br /&gt;&lt;br /&gt;No particular reason, just felt like it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-5663841807506845621?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/5663841807506845621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=5663841807506845621' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/5663841807506845621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/5663841807506845621'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2009/02/php-input-cleaning.html' title='PHP Input Cleaning'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-1905823437735467465</id><published>2008-08-31T14:56:00.003-06:00</published><updated>2010-04-19T15:55:10.768-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='musings'/><title type='text'>Why I hate Idea Men</title><content type='html'>Ever shoot a rifle and miss the target? Well, if you haven't here's how you miss: you're aim is off by just a little bit.&lt;br /&gt;&lt;br /&gt;The same thing happens when you're building software - or anything, for that matter.&lt;br /&gt;&lt;br /&gt;I've spent about 40 years building systems of various kinds - mostly software implementations to 'solve' some problem. The process is pretty straightforward and goes like this:&lt;br /&gt;&lt;br /&gt;1. Try to figure out what you're going to do.&lt;br /&gt;2. Pick the most important parts and the most important actions and interactions between the parts.&lt;br /&gt;3. Pretend that is all there is in the world and build some software which mimics everything you've thought of. By the way, these parts, actions and interactions are the 'model'.&lt;br /&gt;4. Test it until it works well enough to do the job.&lt;br /&gt;5. Knowing what you now know, go back to step 1 and do it all over again.&lt;br /&gt;6. Repeat step 5.&lt;br /&gt;7. Repeat step 6.&lt;br /&gt;&lt;br /&gt;You get the idea.&lt;br /&gt;&lt;br /&gt;Nobody is ever right the first, second, third, or even the 'last' time.&lt;br /&gt;&lt;br /&gt;Models aren't reality - we just work on them until they are 'close enough'.&lt;br /&gt;&lt;br /&gt;What's this got to do with Idea Men?&lt;br /&gt;&lt;br /&gt;Idea Men do parts 1 and 2, then they get somebody else to do step 3.&lt;br /&gt;&lt;br /&gt;Then they blame the guys who built the thing in step 3 because they don't want to do step 4.&lt;br /&gt;&lt;br /&gt;Finally, they won't do step 5 because they're 'right' and the guys who built it are all incompetent and that's the reason it doesn't work like they said it would.&lt;br /&gt;&lt;br /&gt;Then the Idea Men get promotions and raises.&lt;br /&gt;&lt;br /&gt;Crap&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-1905823437735467465?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/1905823437735467465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=1905823437735467465' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/1905823437735467465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/1905823437735467465'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2008/08/why-i-hate-idea-men.html' title='Why I hate Idea Men'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-5447925221525081902</id><published>2008-07-01T09:58:00.007-06:00</published><updated>2010-04-19T15:54:21.623-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>Singleton Patterns in PHP 5</title><content type='html'>The Singleton Pattern is one of the few things I &lt;span style="font-style: italic;"&gt;really&lt;/span&gt; like from Design Patterns. While the original Gang of Four book has some very good stuff in it, later works seem like Software Industry Marketing Fluff [SIMF] - but I've already bitched about that.&lt;br /&gt;&lt;br /&gt;The Singleton is GREAT because it can replace Global Variables - if not everywhere, at least in a lot of important cases.&lt;br /&gt;&lt;br /&gt;In case you don't know what a Singleton is, it's an Object which has only one instance. Ideally, you would like to write something like&lt;br /&gt;&lt;blockquote&gt;$foo = new Thing();&lt;/blockquote&gt;and get a reference to the one instance of Thing.&lt;br /&gt;&lt;br /&gt;The "normal" way to implement the Singleton Pattern is to hack up the class definition in an unnatural way:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Disable the normal constructor by making it private&lt;/li&gt;&lt;li&gt;Define a class variable to hold the One Instance&lt;/li&gt;&lt;li&gt;Create a different public function which is used to instantiate the first instance and return it on all subsequent 'instantiations'&lt;/li&gt;&lt;/ul&gt;This is because none of the Object Oriented Languages directly support Singleton - except  Ruby which has a Singleton base class so you can create them by normal inheritance.&lt;br /&gt;&lt;br /&gt;I was so taken with Ruby's Singleton base class, I decided to write one in PHP 5.&lt;br /&gt;&lt;br /&gt;Drum Roll........&lt;br /&gt;&lt;br /&gt;Didn't work. Failed Miserably.&lt;br /&gt;&lt;br /&gt;It turns out that in PHP 5.2 static class variables [that is, Class Variables] are always in the base class.  I won't go into that here. Instead, take a look at this &lt;a href="http://www.clove.com/downloads/bad-singletons.html"&gt;test&lt;/a&gt; I wrote.&lt;br /&gt;&lt;br /&gt;Anyway, just because we can't build a base class for Singleton Objects, doesn't mean we can't clean up their creation. &lt;a href="http://www.clove.com/downloads/good-singletons.html"&gt;Here&lt;/a&gt; is an example of a pseudo-Singleton which allows me to write&lt;br /&gt;&lt;blockquote&gt;$foo = new Thing();&lt;/blockquote&gt;&lt;br /&gt;and have a $foo object which acts just like a Singleton even though it has many instances.&lt;br /&gt;&lt;br /&gt;The reason this works is that we don't &lt;span style="font-style: italic;"&gt;need&lt;/span&gt; a single instance of the Object. What we need is a reference which returns the common data, where the methods act on the common data, where modification of the common data is seen by all existing references.&lt;br /&gt;&lt;br /&gt;The Pseudo-Singleton looks, acts, and smells like a Singleton, except it is more convenient and natural to use.&lt;br /&gt;&lt;br /&gt;The only thing better would be a 'singleton' keyword prefix to use in 'class' definitions.&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-5447925221525081902?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/5447925221525081902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=5447925221525081902' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/5447925221525081902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/5447925221525081902'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2008/07/singleton-patterns-in-php-5.html' title='Singleton Patterns in PHP 5'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-6798844531766196139</id><published>2008-06-21T22:14:00.003-06:00</published><updated>2010-04-19T15:55:10.768-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='musings'/><title type='text'>Reality and Stuff Like That</title><content type='html'>Believe it or not, I spend far too much time thinking about what is real and what isn't.&lt;br /&gt;&lt;br /&gt;It seems a lot of people seem to think that there are lots of realities and lots of equally valid versions of Truth. This seems like fuzzy thinking to me. So fuzzy that it just doesn't make any sense. [where are you going to put all these versions of Truth - if there isn't a universal Truth which contains them all?]&lt;br /&gt;&lt;br /&gt;Anyway, here's what I've come up with: (nothing original here - much stolen from Lao Tzu's work)&lt;br /&gt;&lt;br /&gt;The first thing to be clear about is 'how do we think'. 'Cause if we understand that, then we can understand what we think is 'real'.&lt;br /&gt;&lt;br /&gt;As nearly as I can tell, we start out by classifying stuff as 'this' and 'everything else'. Some people call this 'dualistic thinking', but my opinion is that it's simply a way to simplify the cacophony of sensory input we are inundated with. It also lets us find 'patterns' so we can form 'habits' to simplify plodding though daily life.&lt;br /&gt;&lt;br /&gt;Anyway, when you add some properties to these 'classifications', you get a 'model'. It's a model because the 'thing' has behaviors associated with it. Like a window lets in light and a tea pot holds tea.&lt;br /&gt;&lt;br /&gt;The BIG CATCH is when we confuse the 'model's we construct with the real world we live in. The 'model' world is really an illusion we've created - but which we treat as real.&lt;br /&gt;&lt;br /&gt;What is 'reality'? That's tough because we're so used to classifying, finding patterns, and creating models that we aren't equipped to perceive - let alone process - what's actually out there.&lt;br /&gt;&lt;br /&gt;Anyway - that's what I think is going on. It also answers the quest of  why we argue so much:&lt;br /&gt;&lt;blockquote&gt;we're all living in different illusions - not different realities - and our illusions are only loosely based on 'reality'.&lt;/blockquote&gt;There are a lot of conclusions you can draw from this - but this is plenty for now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-6798844531766196139?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/6798844531766196139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=6798844531766196139' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/6798844531766196139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/6798844531766196139'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2008/06/reality-and-stuff-like-that.html' title='Reality and Stuff Like That'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-1781578789092677533</id><published>2008-04-23T09:11:00.003-06:00</published><updated>2010-04-19T15:56:39.612-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='s/w opinions'/><title type='text'>ORM's or not?</title><content type='html'>In my quest for a CMS I can not only stand but want to embrace, I've spent the last couple of weeks messing with Drupal.&lt;br /&gt;&lt;br /&gt;Drupal is impressive - at the very least in scope and participation. I like quite a bit of it. In contrast with Rails, Drupal releases seem to be Designed rather than Grown - which is a very strong plus. [I'm not sure I can stand it, but that's another story.]&lt;br /&gt;&lt;br /&gt;But I'm not writing to Praise Drupal, but to make an observation about Object Relational data Mappers.&lt;br /&gt;&lt;br /&gt;Drupal through 6 doesn't have an ORM. They have two 'database adapters' and opt to use SQL. Most of the SQL used for CRUD operations is standard, so that works just fine. I'm told there is discussion in the development forums about stuffing a layer of abstraction in the database code - which I read as 'create an ORM.'&lt;br /&gt;&lt;br /&gt;Looking over the landscape littered with the corpses of ORMs in almost every conceivable (computer) language, should give pause - at least it does to me.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Why do we ORM?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Well, we have to have the data tables in the Database match up with the Attributes in the Objects, don't we?&lt;br /&gt;&lt;br /&gt;Well, No we don't.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;There's no reason for the Data Tables to model our 'business process'. That's a knee jerk reaction taught as gospel in C.S. courses.&lt;br /&gt;&lt;br /&gt;Couple of Facts:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Databases are really good at holding, retrieving, searching, and sorting vast quantities of data. Programming Languages aren't.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Programming Languages are really good manipulating, displaying, inputing, validating, mashing, spindling, and folding data. Databases aren't.&lt;/li&gt;&lt;/ul&gt;Now for a Web Site, much of the content doesn't have a long life, is retrieved by simple, well known searches, ordered by well known sorts, and is displayed in small chunks.&lt;br /&gt;&lt;br /&gt;It seems to me that there much of the data used in a web site could be modeled exclusively in the Programming Language and then serialized in XML or JSON for storage in the database. That separates the representation of the data in the application from the representation in long term storage and obviates the need for an ORM.&lt;br /&gt;&lt;br /&gt;I like that idea so much, I'm building one now just to see how it works in practice.&lt;br /&gt;&lt;br /&gt;Stay Tuned&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-1781578789092677533?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/1781578789092677533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=1781578789092677533' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/1781578789092677533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/1781578789092677533'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2008/04/orms-or-not.html' title='ORM&apos;s or not?'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-7220117839743915315</id><published>2008-03-28T09:17:00.005-06:00</published><updated>2010-04-23T10:40:31.303-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='s/w opinions'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>DRY versus WET</title><content type='html'>You've got to have either a Snappy Acronym or Fancy Vague Phrase (FVP) in order be credible. So when I decided to write about what I think is wrong with DRY, I came up with 'DRY versus WET' - but I didn't know what WET meant.&lt;br /&gt;&lt;br /&gt;DRY - Don't Repeat Yourself - is one of the Mantras of the Current Age of Programming Wisdom.&lt;br /&gt;&lt;br /&gt;In case you don't know what a mantra is, it's a sound or phrase which you repeat over and over again while meditating. Meditating is something you do with your mind which brings peace and quiet . . . by avoiding all thought.&lt;br /&gt;&lt;br /&gt;The problem I have with DRY is that you have to Think in order to write Good Code. In other words, you need Well Examined Thought - that's where WET comes from. [So now I've got an Acronym that Actually Means Something].&lt;br /&gt;&lt;br /&gt;For Example:&lt;br /&gt;&lt;br /&gt;Take a look at the Rails source code to see what over-DRY-ness does. After a while you'll see that (almost) every piece of code which could be repeated is turned into a method call. Even stuff which isn't more than a fraction of a line! This is Really DRY  - so It Must Be Good. Right? Wrong!&lt;br /&gt;&lt;br /&gt;This is Spaghetti [see &lt;a href="http://expressedopinions.blogspot.com/2008/03/new-spaghetti.html"&gt;The New Spaghetti&lt;/a&gt; for more ranting . . I mean 'detail'].&lt;br /&gt;&lt;br /&gt;Historical Note: Spaghetti code originally referred to the overuse of GOTO (or branch) statements in FORTRAN or Assembler programs, but any program which has a high ratio of Control Transfer statements to Useful Work is really Spaghetti - because it reads like all the code was written on the sides of noodles and then all mixed up.&lt;br /&gt;&lt;br /&gt;So . . . Don't DRY up. Get WET!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Think it's worth doing a book about?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-7220117839743915315?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/7220117839743915315/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=7220117839743915315' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7220117839743915315'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/7220117839743915315'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2008/03/dry-versus-wet.html' title='DRY versus WET'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-8940542649156302849</id><published>2008-03-13T17:18:00.004-06:00</published><updated>2010-04-23T10:40:31.303-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='s/w opinions'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>The New Spaghetti</title><content type='html'>Back before Structured Programming - which everyone now thinks is as natural as breathing - we had a thing called 'Spaghetti Code'.&lt;br /&gt;&lt;br /&gt;You wrote Spaghetti Style by using lots of conditional and unconditional GO TO statements to re-use every bit of code you'd written. It was the privative precursor of DRY [Don't Repeat Yourself].&lt;br /&gt;&lt;br /&gt;In those days it kind of made sense - for a couple of reasons:&lt;br /&gt;&lt;br /&gt;1. we didn't know any better&lt;br /&gt;&lt;br /&gt;2. memory was tiny - we measured big machines in KiloBytes and wrote programs using 'overlays' [in case you don't know, an overlay is a chunk of executable code which 'overlays' another chunk in memory. We used to do that because (a) we didn't have enough memory to do the job and (b) there wasn't any automatic memory management]&lt;br /&gt;&lt;br /&gt;The result of Spaghetti Style is that nobody could ever figure out how the programs worked and modifying them was next to impossible.&lt;br /&gt;&lt;br /&gt;What brought this up?&lt;br /&gt;&lt;br /&gt;I've been trying to 'learn Rails' - which is a pretty large Ruby application. Rails has close to 10,000 methods defined, about 1,500 classes, and God only knows what else. The Vocabulary is huge - and so it's a daunting task to say the least.&lt;br /&gt;&lt;br /&gt;On top of the huge vocabulary, there it's DRY.&lt;br /&gt;&lt;br /&gt;That seems to mean that every chunk of code which is used two or more times is ripped out and turned into a method. The result is that in order to do anything, somewhere near one and a half gazillion methods are called. In order to figure out how almost anything works you have to work through a call stack which is makes the old FORTRAN Spaghetti look like a 2nd grader's maze.&lt;br /&gt;&lt;br /&gt;Why is this happening?&lt;br /&gt;&lt;br /&gt;I'm guessing, but I think there are three factors driving this result:&lt;br /&gt;&lt;br /&gt;1. DRY - This is a misunderstanding. DRY is a hip way of saying 'we want to maintain a single point of control so that we don't have to repeat bug fixes in the code'. DRY shouldn't be a mantra, because it's not a Principal of Good Programming. It's a method to implement an idea which is good programming.&lt;br /&gt;&lt;br /&gt;Prior to formulating 'Single Point of Control' as DRY, programmers used some judgement in the size of the methods/functions they wrote. Typical size was 5 to 25 lines or so - enough to do useful work and small enough to be easily understood. Rubyists seem to be addicted to one-line methods which call other methods which call other methods which ... - but they don't Repeat!&lt;br /&gt;&lt;br /&gt;2. Agile Development - This seems to go hand in hand with Test Driven Development. Both sound like good ideas, and they seem to work well for 'throw away' applications - which is what most web sites are. After crawling through the Rails Association Code, I've come to the conclusion something critical has been lost in the Agile-ness of the Development: There's no Design Phase.&lt;br /&gt;&lt;br /&gt;Test Driven Development has proven you don't have to have an overall plan to build code which works. You can build any twisted mess and if you continuously test, it will pass the test.&lt;br /&gt;&lt;br /&gt;But it won't make sense, won't be cohesive, will probably be inefficient, and it will be hell to modify or learn.&lt;br /&gt;&lt;br /&gt;Everything has to be designed it is going to work well and be maintainable. That's true for Buildings, Cars, Motorcycles, Bridges, and, believe it or not, Software.&lt;br /&gt;&lt;br /&gt;3. Ruby itself.&lt;br /&gt;&lt;br /&gt;I love Ruby - almost - because it's a beautiful language and it makes it easy to otherwise hard things. The fact that Ruby is a scripting language means we get instantaneous feedback - and I love that too.&lt;br /&gt;&lt;br /&gt;But both of those things - along with Ruby's openness which allows all kinds of self-modifying code [which seems to be confused with meta-programming] makes it easy to get the illusion of 'doing something' when the programmer is actually just churning different implementations with little impact on improving the goals of the application being developed.&lt;br /&gt;&lt;br /&gt;Does that make sense? If not, read it again.&lt;br /&gt;&lt;br /&gt;Activity != Progress&lt;br /&gt;&lt;br /&gt;It takes discipline and experience to handle as powerful a tool as Ruby is without creating a mess.&lt;br /&gt;&lt;br /&gt;Don't believe me?&lt;br /&gt;&lt;br /&gt;Just take a look at the source for Mongrel and compare [or rather Contrast it] with a bunch of the Rails code. Zed Shaw writes awesome, easily understood code. Somebody in the Rails Core doesn't.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-8940542649156302849?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/8940542649156302849/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=8940542649156302849' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8940542649156302849'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8940542649156302849'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2008/03/new-spaghetti.html' title='The New Spaghetti'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-6275116135548186550</id><published>2008-02-22T07:40:00.005-07:00</published><updated>2010-04-23T10:40:31.303-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Hey Ruby: Where's the Main Program?</title><content type='html'>So as I get deeper into Ruby and Rails, I've found I've been going absolutely &lt;span style="font-style: italic;"&gt;nuts!&lt;/span&gt; trying to understand how the programs work.&lt;br /&gt;&lt;br /&gt;I think I finally figured out my problem. (That's right, it's a problem with ME for a change!)&lt;br /&gt;&lt;br /&gt;There's no 'main' in a Ruby program.&lt;br /&gt;&lt;br /&gt;Most executables - as in /usr/local/bin/foo - are two to ten line Ruby scripts which set up some environment variables and 'require' the 'real' script. The 'real' script usually 'require's a bunch of other scripts, instantiates an object, and calls what appears to be a random method.&lt;br /&gt;&lt;br /&gt;That's it.&lt;br /&gt;&lt;br /&gt;Step back and contrast this with C, Java, Python&lt;super&gt;*&lt;/super&gt;, FORTRAN, COBOL, the Boot Sequence of a computer, ... Need I go on? Everyplace else there is (or pretty much is) a &lt;span style="font-style: italic;"&gt;well known&lt;/span&gt; function, procedure, 'program', file or something where execution &lt;span style="font-style: italic;"&gt;starts&lt;/span&gt; for every program which is written. Even Javascript kicks off with an 'onload' function (except in JQuery, but I think that's really a wrapper).&lt;br /&gt;&lt;br /&gt;Notice I've left out Lisp, Scheme, Smalltalk and a whole bunch of other languages.&lt;br /&gt;&lt;br /&gt;I don't know much about them - from a practical point of view - except that they are interpreted, don't (to my knowledge) have a 'main' entry point, and allow programmers to modify the base system so that it is unique to their program.&lt;br /&gt;&lt;br /&gt;Now, I know someone might argue that all Ruby programs start by firing up the interpreter and loading the environment, so I'm &lt;span style="font-style: italic;"&gt;wrong&lt;/span&gt; - as usual. But that's not what I'm talking about.&lt;br /&gt;&lt;br /&gt;'main' is the start of the logic of the program. Knowing this gives (the generic) you a place to start unraveling the logic of a program. This seems like a 'good thing' (trade mark), but is it?&lt;br /&gt;&lt;br /&gt;The whole idea of 'main' was really invented so that other programs (loaders) would know where to start executing a program. This is a 'convenience' with compiled programs: programs where the source code is processed into (possibly virtual) machine instructions and then further processed into an executable image saved in a file. This executable image is then loaded, source code agnostically, into the execution environment of a computer and run. It's a simple fact that the 'loader' needs a place to start and it doesn't know from beans about the source code - hence the well known 'main'.&lt;br /&gt;&lt;br /&gt;You don't need this for interpreted, dynamic languages, but the S/W community seems to have carried this structure forward.&lt;br /&gt;&lt;br /&gt;I think Ruby represents a significant break from this architecture.&lt;br /&gt;&lt;br /&gt;Ruby 'programs' seem to be a bunch of symbiotic objects, executing in a common (probably specialized) runtime environment. Various behaviors (programs) can be achieved by instantiating different objects and calling appropriate 'starting' methods. This is similar to, but much more fluid than, writing a program within the constraints of a published API for, say, Windows, or a purchased library.&lt;br /&gt;&lt;br /&gt;I like it.&lt;br /&gt;&lt;br /&gt;I don't know how to understand it easily yet, nor do I think anyone really knows how to &lt;span style="font-style: italic;"&gt;document&lt;/span&gt; it yet, but I think it's an advance.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;* Python really doesn't have a 'main' either, but it has taken the 'flavor' of 'main' stipulating that code can be conditionally executed if it is 'run' as though it were the 'main' program AND a chunk of code is included of the form:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;  some code&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This chunk typically goes at the bottom and is encouraged when the code in the file can server either as the basis for a stand-alone program or an importable unit to another OR for testing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-6275116135548186550?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/6275116135548186550/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=6275116135548186550' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/6275116135548186550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/6275116135548186550'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2008/02/hey-ruby-wheres-main-program.html' title='Hey Ruby: Where&apos;s the Main Program?'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-4464823018798122476</id><published>2008-01-27T07:32:00.000-07:00</published><updated>2010-04-19T15:56:39.613-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='s/w opinions'/><title type='text'>DSL Design - that's Domain Specific Language</title><content type='html'>A Domain Specific Language - for those who &lt;span style="font-style: italic;"&gt;don't&lt;/span&gt; know - is a bunch of functions named so that writing function calls 'reads' like natural language. It seems to be sprouting wildly in Ruby - most probably because Ruby doesn't &lt;span style="font-style: italic;"&gt;require&lt;/span&gt; parentheses around function arguments and Ruby programmers are kind of rebels anyway.&lt;br /&gt;&lt;br /&gt;For example:&lt;br /&gt;rabbit_jumps_in_the_hole :hole_size =&gt; 10&lt;br /&gt;&lt;br /&gt;Even if you don't understand Ruby Syntax, you know what the function call does.&lt;br /&gt;&lt;br /&gt;Think of it this way:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Function/methods are really 'verbs'.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Function Options are 'adverbs'&lt;/li&gt;&lt;li&gt;Object Identifiers are 'nouns'&lt;/li&gt;&lt;li&gt;Object Attributes are 'adjectives'&lt;/li&gt;&lt;li&gt;Class Names are 'class names' [gottcha!!!!]&lt;/li&gt;&lt;/ol&gt;I &lt;span style="font-style: italic;"&gt;think&lt;/span&gt; we should think of learning one of these DSL things the same way we think about learning a new Language.&lt;br /&gt;&lt;br /&gt;This can be either a &lt;span style="font-style: italic;"&gt;good&lt;/span&gt; thing or &lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;very bad&lt;/span&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Size Matters&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Which is easier to learn: A language with 10 verbs or one with 1,000?&lt;br /&gt;&lt;br /&gt;Just for the heck of it, I recently tried to get a count of the 'verbs' in Rails 2.0.2. I ran 'egrep -r 'def [a-z]' on all lib directories and came up with:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;actionmailer/lib 694&lt;br /&gt;&lt;/li&gt;&lt;li&gt;actionpack/lib 1393&lt;br /&gt;&lt;/li&gt;&lt;li&gt;activerecord/lib 1134&lt;br /&gt;&lt;/li&gt;&lt;li&gt;activeresource/lib 125&lt;br /&gt;&lt;/li&gt;&lt;li&gt;activesupport/lib 577&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Total 3923&lt;/li&gt;&lt;/ul&gt;In contrast, the Merb Framework is much smaller:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;merb 713&lt;/li&gt;&lt;li&gt;merb.rb 19&lt;/li&gt;&lt;li&gt;tasks.rb 0&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Total 732&lt;/li&gt;&lt;/ul&gt;Of course, this isn't fair because Merb doesn't come with an ORM [Object Relational Mapper library (bunch of database access functions - for those really out of it)] [or Active Record Pattern Implementation, for those . . . - well, you know who you are], so you have to add that in.&lt;br /&gt;&lt;br /&gt;But Merb gives you a choice of ActiveRecord - with it's 1,100 verbs; DataMapper - with about 500 methods; or Sequel - with about 600.&lt;br /&gt;&lt;br /&gt;So learning Merb &lt;span style="font-style: italic;"&gt;should&lt;/span&gt; be &lt;span style="font-style: italic;"&gt;easier&lt;/span&gt; than Rails because the vocabulary is about 1/3 to 1/2 the size.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Synonyms are Bad&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Which is easier to Learn: a language with one word for each concept or with two or more?&lt;br /&gt;&lt;br /&gt;A programming language or environment &lt;span style="font-style: italic;"&gt;isn't&lt;/span&gt; meant for composing poetry, novels, or movies. It's supposed to precisely express a procedure. Period. It should be concise. That makes it &lt;span style="font-style: italic;"&gt;easier&lt;/span&gt; for Programmers to understand.&lt;br /&gt;&lt;br /&gt;Case closed. DSL's should be concise, singular, and boring - but very, very accurate.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Corollary:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The&lt;span style="font-weight: bold;"&gt; Rails Inflector&lt;/span&gt; is a mistake in every possible way:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It Expands rather than Tightens the vocabulary of the Rails DSL&lt;/li&gt;&lt;li&gt;It injects confusion because Programmers now &lt;span style="font-style: italic;"&gt;have&lt;/span&gt; to worry about singular and plural forms depending on context&lt;/li&gt;&lt;li&gt;It doesn't work:&lt;ul&gt;&lt;li&gt;'XMLClass'.underscore -&gt; 'xml_class'&lt;/li&gt;&lt;li&gt;'XMLClass'.underscore.camelize =&gt; 'XmlClass'&lt;/li&gt;&lt;li&gt;'slave'.pluralize == 'slaves'&lt;/li&gt;&lt;li&gt;'slave'.pluralize.singularize == 'slafe'&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;It wastes lots of cycles doing it - machine, programmer, and learning&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Distance is Good&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm talking about the &lt;span style="font-style: italic;"&gt;distance&lt;/span&gt; between words. For example &lt;span style="font-style: italic;"&gt;frog&lt;/span&gt; is very close to &lt;span style="font-style: italic;"&gt;frogs&lt;/span&gt; but far from &lt;span style="font-style: italic;"&gt;toads&lt;/span&gt;. That makes it easier to tell a &lt;span style="font-style: italic;"&gt;frog&lt;/span&gt; from a &lt;span style="font-style: italic;"&gt;toad&lt;/span&gt; in print than in real life.&lt;br /&gt;&lt;br /&gt;Good DSL design should &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; only use &lt;span style="font-style: italic;"&gt;expressive&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;concise&lt;/span&gt; identifiers, but should also keep them far apart, especially when the referents do significantly different things.&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Again, picking on Rails, the methods &lt;span style="font-style: italic;"&gt;update_attribute(attribute)&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;update_attributes(attributes)&lt;/span&gt; are very close together, but one bypasses attribute Validation. Can you tell which one by the names? Don't you think it's important to know?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;DSL is Not Documentation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Most DSL seem to grow more or less organically. The Ruby universe is filled a lot of apparently useful packages with virtually no documentation. Almost all of them have fairly reasonable API documentation - which allows 'one' to learn what each of the 'verbs' in the DSL do, but that's like learning to drive a car by reading Glossary of the Parts! It Just Don't Work.&lt;br /&gt;&lt;br /&gt;It's hard as hell to learn a system without some sense of what the thing is supposed to be doing and how it's put together.&lt;br /&gt;&lt;br /&gt;Don't belive me?&lt;br /&gt;&lt;br /&gt;Figure out a Car from stuff like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Wheel&lt;/span&gt; - 1. circular object in contact with ground; 2. circular object interfacing driver to directional controls.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Nut&lt;/span&gt; - 1. Device for attaching wheel; 2. driver in other automobile; 3. nutritious snack&lt;br /&gt;etc.&lt;br /&gt;&lt;br /&gt;That's API doc and that's what you've got when &lt;span style="font-style: italic;"&gt;all&lt;/span&gt; there is is the DSL.&lt;br /&gt;&lt;br /&gt;'nuff for now&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-4464823018798122476?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/4464823018798122476/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=4464823018798122476' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/4464823018798122476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/4464823018798122476'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2008/01/dsl-design-thats-domain-specific.html' title='DSL Design - that&apos;s Domain Specific Language'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-4592585693872191095</id><published>2008-01-25T09:36:00.000-07:00</published><updated>2010-04-19T15:56:39.614-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='s/w opinions'/><title type='text'>Is Java Bad for You?</title><content type='html'>How do Heavily Constrained programming environments - such as Java, C#, and friends - effect our thinking and creativity?&lt;br /&gt;&lt;br /&gt;I think the goal of heavy constraints and requirements started out as a way to get better code by automatically checking as much stuff as possible mechanically. It all started with compile time type checking and has extended into things I don't want to know about.&lt;br /&gt;&lt;br /&gt;Anyway, the result is that it's hard to write code with these tools. From what I hear - and I don't do Java, C#, and friends - the 'programmers' spend most of their time figuring out what API's and Design Patterns to use. I don't find that fun at all.&lt;br /&gt;&lt;br /&gt;I usually spend most of my time trying to better understand the problems I'm trying to solve and creating software structures which mimic the nature of the problem. After I've coded and tested one of these structures, I call it a 'solution'.&lt;br /&gt;&lt;br /&gt;In other words: I don't use Design Patterns and don't think in terms of API's.&lt;br /&gt;&lt;br /&gt;Does that make me a dinosaur?&lt;br /&gt;&lt;br /&gt;I don't think so.&lt;br /&gt;&lt;br /&gt;I gravitate toward unrestricted programming environments. My first introduction was SCO Xenix around 1986 or 87. I became really excited as I realized how easy it was to do mundane tasks by stringing filters together in pipelines. I could accomplish more useful work in 1/10th the time [or so it seemed] than I could writing special programs to do the same thing.&lt;br /&gt;&lt;br /&gt;In addition to being faster, it was more fun. I spent more and more of my energy solving problems rather than conforming to code writing rules.&lt;br /&gt;&lt;br /&gt;The same thing happened when I discovered Python - and now to a similar extent Ruby. Scripting languages with good support for dynamic strings, arrays, hashes and objects are wonderful. They handle all the details of what I need - as a coder - to do the job.&lt;br /&gt;&lt;br /&gt;How do I keep from hurting myself when the Programming Environment doesn't keep tabs on me?&lt;br /&gt;&lt;br /&gt;Well, it's not a problem. I just test as I go and keep rewriting my code so it works, is more succinct, and tighter. [I guess you call that Refactoring now - we used to call it rewriting]&lt;br /&gt;&lt;br /&gt;The facts are that Anyone can write bad code - and restrictive frameworks don't stop them. Anyone can also write good code - if they take the time to learn how and pay attention to what they are doing. And restrictive languages don't help with that either.&lt;br /&gt;&lt;br /&gt;When I need a solution - I just think one up (or two or three) up and try it out. It's easy to write the code, change it, test it, and refine it. In a verbose, API laden environment like Java, that cycle isn't so easy - or at least is a heck of a lot more verbose.&lt;br /&gt;&lt;br /&gt;I suspect that restrictive environment programmers get dulled down by the drudgery of just writing the code and learning all the API's. There is so little room for creativity that they lose it - creativity is something you have to practice and cultivate.&lt;br /&gt;&lt;br /&gt;As a result, they get used to solving problems by applying packages and patterns. They don't really design: they apply old designs to new problems and hope that they work. [BTW, that's the reality behind Anti-Patterns]&lt;br /&gt;&lt;br /&gt;So, I guess it makes sense: if everything you do is a cut-and-paste of something somebody else thought up, you would apply that to Design as well.&lt;br /&gt;&lt;br /&gt;God, that's boring!&lt;br /&gt;&lt;br /&gt;If I'm write, then Design Patterns are a result of Boring Programming Tools which create Bored, Dull Programmers and more Bad Code.&lt;br /&gt;&lt;br /&gt;I don't think that's a good thing.&lt;br /&gt;&lt;br /&gt;What do you think?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-4592585693872191095?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/4592585693872191095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=4592585693872191095' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/4592585693872191095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/4592585693872191095'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2008/01/is-java-bad-for-you.html' title='Is Java Bad for You?'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-6137326466480761659</id><published>2008-01-09T11:08:00.001-07:00</published><updated>2010-04-23T10:40:31.304-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Code Efficiency in Ruby</title><content type='html'>I got interested in the qualify of Ruby code in Rails when I noticed what appears to me to be a useless method in the ActiveRecord code. Specifically, ActiveRecord::Base.save is a public method which calls the private method ActiveRecord::Base#create_or_update. That doesn't make a lot of sense to me, because it could be replaced by making 'create_or_update' public and then aliasing 'save' to it.&lt;br /&gt;&lt;p&gt;So I decided to check to see what the superfluously method call costs.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I wrote a test which performed a simple task [incrementing an instance variable by a random number between 1 and 10] using five (5) different ways of accessing the instance variable and invoking the action.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The class definition is at the bottom of this post.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I then ran these methods 10,000,000 times using four different ways of invoking the methods:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;directly calling the methods - e.g. foo.inc_instance_variable()&lt;/li&gt;&lt;br /&gt;&lt;li&gt;invoking via the method's 'call' attribute - e.g. foo.inc_instance_variable.call()&lt;/li&gt;&lt;br /&gt;&lt;li&gt;invoking via the method via 'send' - e.g. foo.send('inc_instance_variable')&lt;/li&gt;&lt;br /&gt;&lt;li&gt;invoking via 'eval'ing the string - e.g. eval 'foo.inc_instance_variable'&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The Precent Results are simply the run time divided by the minimum run time for all tests converted to a percent increase.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Here's the summary:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Invoking via an Alias doesn't cost anything&lt;/li&gt;&lt;br /&gt;&lt;li&gt;unnecessarily accessing an instance Variable via an accessor slows down about 20%&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The unnecessary method/function call slows down by about 25%&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Combining the unnecessary call with accessor access slows down about 45% - so the effect is linear&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Invoking by the 'call' method slows it down by about 13%&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Using 'send' slows down about an additional 45%&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Using eval slows the process down by something on the order of 400%, but the effect is not linear, so 'eval' must be doing some additional mucking about.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So, what's the point? None, if you're satisfied with glacial execution speeds.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;On the other hand, it's something you should know if you are writing critical code and have to make choices about how to implement it.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;As usual, your mileage may vary. The full program code is at http://www.clove.com/downloads/method-call-timing-tests.rb.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Here are the detailed Percentage Results&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;Percent Results for direct method of invocation&lt;br /&gt;foo.inc_var_as_instance                   0.99&lt;br /&gt;foo.inc_var_as_instance_alias             0.00&lt;br /&gt;foo.inc_var_as_method                    19.89&lt;br /&gt;foo.inc_var_as_func_and_instance         25.28&lt;br /&gt;foo.inc_var_as_func_and_method           45.17&lt;br /&gt;&lt;br /&gt;Percent Results for call method of invocation&lt;br /&gt;foo.inc_var_as_instance                  14.06&lt;br /&gt;foo.inc_var_as_instance_alias            12.93&lt;br /&gt;foo.inc_var_as_method                    32.53&lt;br /&gt;foo.inc_var_as_func_and_instance         42.19&lt;br /&gt;foo.inc_var_as_func_and_method           59.52&lt;br /&gt;&lt;br /&gt;Percent Results for send method of invocation&lt;br /&gt;foo.inc_var_as_instance                  42.05&lt;br /&gt;foo.inc_var_as_instance_alias            46.02&lt;br /&gt;foo.inc_var_as_method                    60.65&lt;br /&gt;foo.inc_var_as_func_and_instance         75.57&lt;br /&gt;foo.inc_var_as_func_and_method           94.03&lt;br /&gt;&lt;br /&gt;Percent Results for eval method of invocation&lt;br /&gt;foo.inc_var_as_instance                 393.89&lt;br /&gt;foo.inc_var_as_instance_alias           410.94&lt;br /&gt;foo.inc_var_as_method                   420.03&lt;br /&gt;foo.inc_var_as_func_and_instance        458.10&lt;br /&gt;foo.inc_var_as_func_and_method          577.84&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Here are the raw timing results:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;Result using Direct Calls&lt;br /&gt;foo.inc_var_as_instance   7.070000   0.040000   7.110000 (  7.306318)&lt;br /&gt;foo.inc_var_as_instance_alias   7.000000   0.040000   7.040000 (  7.155283)&lt;br /&gt;foo.inc_var_as_method   8.390000   0.050000   8.440000 (  8.585970)&lt;br /&gt;foo.inc_var_as_func_and_instance   8.780000   0.040000   8.820000 (  8.950350)&lt;br /&gt;foo.inc_var_as_func_and_method  10.160000   0.060000  10.220000 ( 10.378127)&lt;br /&gt;&lt;br /&gt;Result using &lt;foo&gt;.call&lt;br /&gt;foo.inc_var_as_instance   7.990000   0.040000   8.030000 (  8.204646)&lt;br /&gt;foo.inc_var_as_instance_alias   7.910000   0.040000   7.950000 (  8.061320)&lt;br /&gt;foo.inc_var_as_method   9.280000   0.050000   9.330000 (  9.502992)&lt;br /&gt;foo.inc_var_as_func_and_instance   9.940000   0.070000  10.010000 ( 10.249010)&lt;br /&gt;foo.inc_var_as_func_and_method  11.170000   0.060000  11.230000 ( 11.439927)&lt;br /&gt;&lt;br /&gt;Result using 'foo.send &lt;func&gt;'&lt;br /&gt;foo.inc_var_as_instance   9.950000   0.050000  10.000000 ( 10.220120)&lt;br /&gt;foo.inc_var_as_instance_alias  10.220000   0.060000  10.280000 ( 10.462063)&lt;br /&gt;foo.inc_var_as_method  11.250000   0.060000  11.310000 ( 11.514329)&lt;br /&gt;foo.inc_var_as_func_and_instance  12.290000   0.070000  12.360000 ( 12.583919)&lt;br /&gt;foo.inc_var_as_func_and_method  13.590000   0.070000  13.660000 ( 13.891333)&lt;br /&gt;&lt;br /&gt;Result using 'eval &lt;foo&gt;'&lt;br /&gt;foo.inc_var_as_instance  34.550000   0.220000  34.770000 ( 35.387702)&lt;br /&gt;foo.inc_var_as_instance_alias  35.740000   0.230000  35.970000 ( 36.670451)&lt;br /&gt;foo.inc_var_as_method  36.390000   0.220000  36.610000 ( 37.296297)&lt;br /&gt;foo.inc_var_as_func_and_instance  39.050000   0.240000  39.290000 ( 40.033456)&lt;br /&gt;foo.inc_var_as_func_and_method  47.420000   0.300000  47.720000 ( 48.638035)&lt;br /&gt;&lt;/foo&gt;&lt;/func&gt;&lt;/foo&gt;&lt;/pre&gt;&lt;p&gt;Here's the class definition:&lt;br /&gt;&lt;/p&gt;&lt;pre style="font-family: sans-serif;"&gt;class Foo&lt;br /&gt;attr_accessor :var&lt;br /&gt;&lt;br /&gt;def initialize&lt;br /&gt; @var = 0&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# access the instance variable directly&lt;br /&gt;def inc_var_as_instance&lt;br /&gt; @var = @var + 1 + rand(10)&lt;br /&gt;end&lt;br /&gt;# access instance variable directly, but us an alias&lt;br /&gt;alias_method :inc_var_as_instance_alias, :inc_var_as_instance&lt;br /&gt;&lt;br /&gt;# access instance via accessor method, even though inside class instance&lt;br /&gt;def inc_var_as_method&lt;br /&gt; self.var = self.var + 1 + rand(10)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;public&lt;br /&gt;# add an additional method call to accessing via direct access to instance variable&lt;br /&gt;def inc_var_as_func_and_instance&lt;br /&gt; inc_var_as_instance&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# add an additional method call to accessing via accessor&lt;br /&gt;def inc_var_as_func_and_method&lt;br /&gt; inc_var_as_method&lt;br /&gt;end&lt;br /&gt;end&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/3666775354459763953-6137326466480761659?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/6137326466480761659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=6137326466480761659' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/6137326466480761659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/6137326466480761659'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2008/01/code-efficiency-in-ruby.html' title='Code Efficiency in Ruby'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-8762900608763785181</id><published>2008-01-05T11:19:00.000-07:00</published><updated>2010-04-19T15:56:39.614-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='s/w opinions'/><title type='text'>Design Patterns and the Fall of S/W</title><content type='html'>One nice thing about having a blog nobody reads is that I can say anything I want without worrying about it biting my butt.&lt;br /&gt;&lt;br /&gt;I hate Design Patterns.&lt;br /&gt;&lt;br /&gt;It's that simple.&lt;br /&gt;&lt;br /&gt;I hate the guys who promote them.&lt;br /&gt;&lt;br /&gt;Most of all, I hate the s/w industry - especially the programmers - for being duped by these guys.&lt;br /&gt;&lt;br /&gt;And I'm qualified.&lt;br /&gt;&lt;br /&gt;I received an engineering education and am a self taught computer 'something'. I'm not exactly a programmer, although I've written an awfully lot of code in a variety of environments - all the way down to machine code on microprocessors up to hokey database/user interface stuff. I've done device drivers and created my own little languages using lex &amp;amp; yacc and 'in the raw' in C, Python, and awk. And I've been doing this over 40 years - so I've earned the right to be a grouch.&lt;br /&gt;&lt;br /&gt;The Design Pattern guys are the current generation of Yordon (sp?), Codd(sp?), and Bouch (sp?): Consultants who &lt;span style="font-style: italic;"&gt;watch&lt;/span&gt; other people create software while &lt;span style="font-style: italic;"&gt;telling&lt;/span&gt; them how to do it &lt;span style="font-style: italic;"&gt;right&lt;/span&gt;. None of them actually &lt;span style="font-style: italic;"&gt;do&lt;/span&gt; anything, but the sure create a lot of bad advice.&lt;br /&gt;&lt;br /&gt;I remember buying three (3!) books by Peter Codd(sp?) on Object oriented programming and design &lt;span style="font-style: italic;"&gt;only to find out that he admitted that he didn't really know anything about it.&lt;/span&gt; The idiot had gotten excited about the idea, so he and his group spent a year puttering with it and writing books - probably giving lectures and doing expensive consulting with BIG companies at the same time.&lt;br /&gt;&lt;br /&gt;It takes years of experience doing something to understand the concepts. [things move quickly, but our brains take a while to catch up]. Hell, it takes 10 years plus to design, implement, and knock most of the bugs out of &lt;span style="font-style: italic;"&gt;any&lt;/span&gt; programming language.&lt;br /&gt;&lt;br /&gt;The Design Pattern guys are the absolute &lt;span style="font-style: italic;"&gt;worst!&lt;/span&gt; The &lt;span style="font-style: italic;"&gt;claim&lt;/span&gt; that they are defining these things to add clarity to the software process and they they write the vaguest crap imaginable. Don't believe me?&lt;br /&gt;&lt;br /&gt;Grady Bouch: "In the world of software, a pattern is a tangible manifestation of an orginization's tribal memory." - CoreJ2EE Patterns (introduction) [clipped from PHP 5 Objects, Patterns, and Practice - by Matt Zandstra]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Merrian Webster Dictionary: "1. an ideal model. 2. something used as a model for making things. 3. Sample"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Which is clearer? If you like Bouch - then you need to join a consulting company and stop pretending to write code.&lt;br /&gt;&lt;br /&gt;I'm starting to froth at the mouth, so it's time to simplify things. Here's a simple procedure to see for yourself.&lt;br /&gt;&lt;br /&gt;1. go to a book store and pick up one of Martin Fowler's many books on patterns. WARNING: Do &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; buy the book.&lt;br /&gt;&lt;br /&gt;2. Select a pattern at random and read the first paragraph describing it.&lt;br /&gt;&lt;br /&gt;3. Answer yourself honestly: Do I know what this 'pattern' is well enough to describe it in a single sentence?&lt;br /&gt;&lt;br /&gt;if No - read the rest of the description and try again&lt;br /&gt;&lt;br /&gt;if still No - replace book on shelf.&lt;br /&gt;&lt;br /&gt;if Yes, please send that sentence to me.&lt;br /&gt;&lt;br /&gt;Thanks,&lt;br /&gt;Mike&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-8762900608763785181?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/8762900608763785181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=8762900608763785181' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8762900608763785181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8762900608763785181'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2008/01/design-patterns-and-fall-of-sw.html' title='Design Patterns and the Fall of S/W'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-670415542454306234</id><published>2007-11-11T08:49:00.000-07:00</published><updated>2007-11-11T10:13:01.299-07:00</updated><title type='text'>What's the Best Web Site Builder</title><content type='html'>I don't think it exists yet.&lt;br /&gt;&lt;br /&gt;There is a parallel between Web Site Frameworks (and friends) and Operating Systems and I think we can build better web site development systems if we're aware of it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;About OS's  &lt;/span&gt;(at a really light level)&lt;br /&gt;&lt;br /&gt;Operating systems really stated out as Monitor programs which allowed a 1950s and '60s 'programmer' to load and run one program at a time on the monster sized, minuscule capable early machines. They sucked, but it was better than programming in machine code.&lt;br /&gt;&lt;br /&gt;The big advantage Monitors gave was that if you upgraded the hardware, you reflected the change in the Monitor and your old programs still ran. MS-DOS and CP-M were really Monitors, not operating systems.&lt;br /&gt;&lt;br /&gt;Then smart people developed the idea of an Operating System. One problem with Monitors is that they didn't have any way to recover control of the hardware when the application program went into a infinite loop or some other destructive mode. OS's had an executive module which allowed the program to run. It regained control periodically and decided whether or not to kill the program or let it run. In other words, you had to get permission from the OS to run your program. It sat there like a despot, completely controlling what you could and couldn't do and how long you could do it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;To get Back to Web &lt;/span&gt;development, I think we're at the 'early-ish OS stage'.&lt;br /&gt;&lt;br /&gt;We've already gone through the Machine Code and Assembler Language stage with raw HTML and doing everything with Tables. Monitors roughly correspond to writing everything by hand - with or without a tool like Dreamweaver - one site at a time.&lt;br /&gt;&lt;br /&gt;Drupal, Rails, Joomla!, and friends look very much to me like early OS's. When a request goes to the server, it is caught by the framework's machinery. The framework (read OS executive/sultan/king) then decides what to do with it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;So What's the Point?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What's the most successful OS model of all time? UNIX!&lt;br /&gt;&lt;br /&gt;Why?&lt;br /&gt;&lt;br /&gt;UNIX gave Choice to the Programmers and took it away from the OS Designers.&lt;br /&gt;&lt;br /&gt;UNIX was a fundamentally different from the other OS's. IBM and everybody else put everything that a good police state needs to control it's citizens &lt;span style="font-style: italic;"&gt;inside&lt;/span&gt; the operating system where nobody could get at it &lt;span style="font-style: italic;"&gt;except&lt;/span&gt; the privileged few. UNIX didn't.&lt;br /&gt;&lt;br /&gt;The UNIX system consisted of two parts: the &lt;span style="font-style: italic;"&gt;kernel&lt;/span&gt;, which provides services for it's citizens and &lt;span style="font-style: italic;"&gt;userspace&lt;/span&gt;, where things are done.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-style: italic;"&gt;kernel&lt;/span&gt; supports and enables. For the most part, it doesn't &lt;span style="font-style: italic;"&gt;control&lt;/span&gt;. All the Executive stuff is in &lt;span style="font-style: italic;"&gt;userspace&lt;/span&gt; which means: &lt;span style="font-style: italic;"&gt;it can be replaced by the people Using the machine if it doesn't do what they want.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is &lt;span style="font-style: italic;"&gt;really important&lt;/span&gt; so I'll repeat it. The &lt;span style="font-style: italic;"&gt;kernel&lt;/span&gt; supplies services, but doesn't &lt;span style="font-style: italic;"&gt;do&lt;/span&gt; anything. It just sits and waits - like a good robot. All the action is in &lt;span style="font-style: italic;"&gt;userspace&lt;/span&gt; and it can be &lt;span style="font-style: italic;"&gt;replaced&lt;/span&gt; if you want something different.&lt;br /&gt;&lt;br /&gt;All the web frameworks I've looked at over the past year and half have the Executive function embedded in the framework. That is, when a request comes it, it's received and processed by the framework. Right now in Web Development, if you want to do something which is not directly supported by your framework, you have three choices:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;hack together some lame work-around&lt;/li&gt;&lt;li&gt;don't do what you want&lt;/li&gt;&lt;li&gt;get another framework&lt;/li&gt;&lt;/ul&gt;It's just like the pre-UNIX days.&lt;br /&gt;&lt;br /&gt;When UNIX came in, it became possible for the Programming Community to build lots of alternate Executive function implementations as &lt;span style="font-style: italic;"&gt;drop in replacements&lt;/span&gt; for the stuff which shipped with the system. Free Market!!! That's why UNIX is a great development environment and why it makes such a great server environment. The Programming Community developed a lot of stuff and kept the stuff which works.&lt;br /&gt;&lt;br /&gt;That couldn't have happened if we'd had to change kernels for every alternative design - or it would have taken a gazillion years longer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Pitch&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;I think we need Web Development &lt;span style="font-style: italic;"&gt;kernel&lt;/span&gt;. I'm working at &lt;a href="http://www.clove.com/FunctionalSpec.html"&gt;spec'ing&lt;/a&gt; one out. I call it uWeb (pronounced 'you Web')&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-670415542454306234?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/670415542454306234/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=670415542454306234' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/670415542454306234'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/670415542454306234'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2007/11/whats-best-web-site-builder.html' title='What&apos;s the Best Web Site Builder'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-5734903402827230409</id><published>2007-11-09T08:06:00.000-07:00</published><updated>2007-11-09T08:19:59.548-07:00</updated><title type='text'>Me and the Leopard</title><content type='html'>I installed Mac OS X 10.5 - aka Leopard - last Saturday (or was it Sunday) and just now finished reverting to 10.4.10. Boy oh Boy, has it been non-Fun.&lt;br /&gt;&lt;br /&gt;Well, it was really my own fault. I know better than to install the initial release of &lt;span style="font-style: italic;"&gt;anything&lt;/span&gt;, but, I'll admit it, I got lulled into wanting it - salivating even - by listening to Steve the Jobs extol Leopard's features. He's really right: they are really neat, look great, and will make using the machine so much easier. So when Leopard came out, I pounced.&lt;br /&gt;&lt;br /&gt;Anyway, skippin’ the boring details:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Printing to my HP All-in-one died dramatically&lt;/li&gt;&lt;li&gt;Time machine doesn't work across a LAN w/o OS X Server - for another $500&lt;/li&gt;&lt;li&gt;'admin' accounts spontaneously became 'standard - Twice&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;So I got scared and spent the next three days reverting back to Tiger. (I finally did an Erase and Install and reinstalled/rebuilt everything)&lt;br /&gt;&lt;br /&gt;I'm waiting for 10.5.1, and then I'll try it again - maybe.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-5734903402827230409?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/5734903402827230409/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=5734903402827230409' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/5734903402827230409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/5734903402827230409'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2007/11/me-and-leopard.html' title='Me and the Leopard'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-8760235371850009042</id><published>2007-11-03T10:24:00.000-06:00</published><updated>2007-11-03T11:02:27.953-06:00</updated><title type='text'>Design Patterns?</title><content type='html'>I was asleep in the country when Design Patterns became popular. It seems now that unless you've had a 'pattern implant' you're not qualified to solve problems.&lt;br /&gt;&lt;br /&gt;This came as a shock to me because I've been analyzing and solving problems for a long time: I escaped Engineering school in '68, '70, and, finally for good, in '72. We didn't have 'design patterns' then. We had principles, experience, and knowledge.&lt;br /&gt;&lt;br /&gt;So what are these things? Are they a good thing or not?&lt;br /&gt;&lt;br /&gt;According to the Wikipedia article on Design Pattern (computer science), a design pattern "... is a description or template for how to solve a problem that can be used in many different situations." &lt;br /&gt;&lt;br /&gt;So far that sounds good, but then I start getting confused:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;design patterns are not algorithms because "algorithms solve computational problems." I didn't know that. I thought algorithms were systematic, iterative procedures which did something - like copy a buffer from one place to another or to find something.&lt;br /&gt;&lt;li&gt;design patterns are not "architectural patterns" because they have a "different scope."&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Then I read some stuff by Martin Fowler describing the Active Record pattern. The thing that came across most strongly is &lt;i&gt;vagueness&lt;/i&gt;. Everything is so indefinite and "could also be ...".&lt;br /&gt;&lt;br /&gt;It all became crystal clear!&lt;br /&gt;&lt;br /&gt;Design Patterns are the current Holy Grail of the Software Methodology Guru.&lt;br /&gt;&lt;br /&gt;As long as I've been beating on computers, there have been Great Gods of Software Design. I used to read their stuff and think I was doing everything wrong because I wasn't doing it their way. So I'd try it and it didn't work very well for me (why later).&lt;br /&gt;&lt;br /&gt;The Software Methodology Gods are really OK guys, but you have to judge their gospel within its context. In other words: what do these guys really do?&lt;br /&gt;&lt;br /&gt;One thing the don't do is actually build the kinds of systems they tell you how to build. Why? Well, they don't have time. They spend their time &lt;i&gt;watching&lt;/i&gt; other teams build things and writing and preaching about what they've observed. At least that's what they are supposed to be doing. [And the reason it didn't work for me is that I've &lt;i&gt;never&lt;/i&gt; worked on a team. All my stuff was in-house, solo or with a partner, limited scope, and very limited user base. Their experience did *not* apply!  see Joel on Software, chapter &lt;i&gt;twelve&lt;/i&gt; "Five Worlds"]&lt;br /&gt;&lt;br /&gt;So these guys' main business is giving advice.&lt;br /&gt;&lt;br /&gt;I'm sure a lot of the advice is pretty good - it has to be if they get from watching teams that do good work. But that doesn't mean it's right 100% of the time and in all cases. Anyway you can't really tell if it works, because there's no way you can compile and execute &lt;i&gt;vagueness&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;OK, I'm a little harsh. It's just that if the advice is vague, then it's usually pretty easy to win the postmortum no matter how things work out - success or failure. If it worked, it's because you followed my advice. If it failed, it's because you didn't. Vaguness covers or &lt;i&gt;excludes&lt;/i&gt; a whole range of implementations.&lt;br /&gt;&lt;br /&gt;Anyway, what happens is this: These guys &lt;i&gt;sound&lt;/i&gt; so confident that I used to get lulled into thinking that they're right and I was wrong. &lt;br /&gt;&lt;br /&gt;What's the result?&lt;br /&gt;&lt;br /&gt;I'd read their stuff and &lt;i&gt;instead&lt;/i&gt; of trying to figure out if it is worth doing in my situation, I'd spend all my time trying to figure out what they're talking about and how to &lt;i&gt;change&lt;/i&gt; what I was doing to be right - according to them.&lt;br /&gt;&lt;br /&gt;I was working my brain, but not on the right problem. (By the way, would you be interested in this really great vacuum cleaner we have on special today?)&lt;br /&gt;&lt;br /&gt;So, here's what I think Design Patterns are good for:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;ideas - look them over and see how somebody else does it&lt;br /&gt;&lt;li&gt;obfuscation - if you know enough of them, you've got a great cryptic language you can use to blow smoke in the other guy's face&lt;br /&gt;&lt;li&gt;writing books and articles - "Design Patterns for ________". Just fill in the blank and you're all set for fame and fortune&lt;br /&gt;&lt;li&gt;getting consulting gigs from non-technical managers&lt;br /&gt;&lt;li&gt;giving courses to programming teams&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;One thing they &lt;i&gt;won't&lt;/i&gt; do is make mediocre and poor programmers productive.&lt;br /&gt;&lt;br /&gt;So what am I going to do now? Well, I'll read the book. There must be &lt;i&gt;something&lt;/i&gt; useful in there. But I'm not going to shut off my brain when I design something.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-8760235371850009042?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/8760235371850009042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=8760235371850009042' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8760235371850009042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/8760235371850009042'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2007/11/design-patterns.html' title='Design Patterns?'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3666775354459763953.post-4922832938327271124</id><published>2007-10-28T15:43:00.000-06:00</published><updated>2007-10-28T16:15:51.440-06:00</updated><title type='text'>Why MVC is Wrong</title><content type='html'>First of all: MVC is Right because the model separates problems into three relatively independent functions.&lt;br /&gt;&lt;br /&gt;But, MVC is wrong because it's being used as though it is the Only way to do things.&lt;br /&gt;&lt;br /&gt;It's Not.&lt;br /&gt;&lt;br /&gt;The problem is that Presupposing or Requiring an MVC model interfers with the Design Process.&lt;br /&gt;&lt;br /&gt;Here's the best way we've found to design and construct systems:&lt;br /&gt;&lt;br /&gt;1. figure out what is to be done and define it precisely and succinctly&lt;br /&gt;&lt;br /&gt;2. define a collection of tasks which can be performed in series or parallel where the results can be either combined or fed to successive tasks which produce the desired result. Ideally, these tasks can be defined as 'black boxes' - to use the term I was taught back in Engineering school.&lt;br /&gt;&lt;br /&gt;3. Build the boxes, test, deploy and celebrate.&lt;br /&gt;&lt;br /&gt;In my experience, every field - Engineering, Computer Science, Economics, etc etc - has rediscovered the same method and principles - but uses different terminology.&lt;br /&gt;&lt;br /&gt;In CS, black boxes were 'objects'. Now they are Design Patterns. We used to talk about Heirarchic Decomposition,  Information Hiding and Structured Programming. In client-server designs, we talk about clients, servers, and protocols.&lt;br /&gt;&lt;br /&gt;It's all the same stuff.&lt;br /&gt;&lt;br /&gt;1. We figure out what we want to do.&lt;br /&gt;&lt;br /&gt;2. Then we chop it into pieces small enough to build.&lt;br /&gt;&lt;br /&gt;3. Then we define some protocol to get inputs into and outputs out of each piece and use them to wire the whole thing together.&lt;br /&gt;&lt;br /&gt;MVC Screws this up mostly because it puts the Chopping before the Analysis. This Adds complexity to the solution rather than taking it away.&lt;br /&gt;&lt;br /&gt;For Example:&lt;br /&gt;&lt;br /&gt;Suppose I have a semi-static web site. By that I mean, nothing changes all that much, but the owner would like to modify something on a couple of pages every once in a while.&lt;br /&gt;&lt;br /&gt;I can Make this MVC, but why bother? There's nothing to Control. All I have are Views. The only 'model' I have is a chunk of Text. Most of my pages can look like:&lt;br /&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt; etc&lt;br /&gt; &amp;lt;?php include('owner-content'); ?&amp;gt;&lt;br /&gt; etc&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;br /&gt;If I have a way for the site owner to update 'owner-content' - possibly a simple update page so she can edit the page on her home machine and then download it to the site - then I'm done.&lt;br /&gt;&lt;br /&gt;I don't need MVC partitioning of this problem unless I want to use a prepackaged system.&lt;br /&gt;&lt;br /&gt;The obvious answer is there isn't any need for all that machinery to solve simple problems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3666775354459763953-4922832938327271124?l=expressedopinions.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://expressedopinions.blogspot.com/feeds/4922832938327271124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3666775354459763953&amp;postID=4922832938327271124' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/4922832938327271124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3666775354459763953/posts/default/4922832938327271124'/><link rel='alternate' type='text/html' href='http://expressedopinions.blogspot.com/2007/10/why-mvc-is-wrong.html' title='Why MVC is Wrong'/><author><name>Mike Howard</name><uri>http://www.blogger.com/profile/13338540788979060878</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://bp3.blogger.com/_FTEqNRKeruo/R5yV7v4XNUI/AAAAAAAAABg/U1PlR0uC-nA/S220/MikePhoto.png'/></author><thr:total>0</thr:total></entry></feed>
