Pablo's blog

A bit of this, a bit of that and a lot about computers

Full URL in Rails’ logs

I find myself needing to have the full URLs in Rails’ logs. Normally you get something like:

Started GET "/" for 127.0.0.1 at 2011-08-27 13:13:10 +0200

but I needed

Started GET "http://foo.bar:3000/" for 127.0.0.1 at 2011-08-27 13:13:10 +0200

because the app does different things depending on the domain and when it fails, I have to know which URL was hit. The solution I ended up with was adding this in an initializer:

class Rails::Rack::Logger << ActiveSupport::LogSubscriber
  protected

  def before_dispatch(env)
    request = ActionDispatch::Request.new(env)
    info "\n\nStarted #{request.request_method} \"#{request.url}\" for #{request.ip} at #{Time.now.to_default_s}"
  end
end

That’s monkey-patching Rails’ own logger. Credit for the solution goes to numbers1311407.

My question for the people using Rails, do you think having a configurable logger in Rails would be useful or nice? If so, I could make a patch for Rails but I have made patches before that failed to gather the needed popularity and thus were ignored. I’m not wasting my time like that again.

How to use Lobos with Heroku

Lobos is a Clojure library to create and alter tables which also supports migrations similar to what Rails can do. I like where Lobos is going but it’s a work in progress, so the information here might be out of date soon, beware!

Let’s imagine a project called px (for Project X of course) with the usual Leiningen structure. In the src directory you you need to create a lobos directory and inside there let’s get started with config.clj which contains the credentials and other database information:

(ns lobos.config)

(def db
  {:classname "org.postgresql.Driver"
   :subprotocol "postgresql"
   :subname "//localhost:5432/px"})

then we create a simple migration in lobos/migrations.clj that creates the users table:

(ns lobos.migrations
  (:refer-clojure :exclude [alter defonce drop bigint boolean char double float time])
  (:use (lobos [migration :only [defmigration]] core schema) lobos.config))

(defmigration create-users
  (up [] (create (table :users
                   (integer :id :primary-key)
                   (varchar :email 256 :unique))))
  (down [] (drop (table :users))))

You run a REPL, load the migrations and run them (using the joyful Clojure example code convention):

(require 'lobos.migrations)
;=> nil
(lobos.core/run)
;=> java.lang.Exception: No such global connection currently open: :default-connection, only got [] (NO_SOURCE_FILE:0)

and you get an error because you didn’t open the connection yet, so, let’s do that:

(require 'lobos.connectivity)
;=> nil
(lobos.connectivity/open-global lobos.config/db)
;=> {:default-connection {:connection #<Jdbc4Connection org.postgresql.jdbc4.Jdbc4Connection@2ab600af>, :db-spec {:classname "org.postgresql.Driver", :subprotocol "postgresql", :subname "//localhost:5432/px"}}}

and now it works:

(lobos.core/run)
; create-users
;=> nil

and you can also rollback:

(lobos.core/rollback)
; create-users
;=> nil

You might be tempted to open the global connection in your config.clj and that might be fine for some, but I found it problematic that the second time I load the file, I get an error: “java.lang.Exception: A global connection by that name already exists (:default-connection) (NO_SOURCE_FILE:0)”.

My solution was to write a function called open-global-when-necessary that will open a global connection only when there’s none or when the database specification changed, and will close the previous connection in that case, leaving a config.clj that looks like:

(ns lobos.config
  (:require lobos.connectivity))

(defn open-global-when-necessary
  "Open a global connection only when necessary, that is, when no previous
  connection exist or when db-spec is different to the current global
  connection."
  [db-spec]
  ;; If the connection credentials has changed, close the connection.
  (when (and (@lobos.connectivity/global-connections :default-connection)
             (not= (:db-spec (@lobos.connectivity/global-connections :default-connection)) db-spec))
    (lobos.connectivity/close-global))
  ;; Open a new connection or return the existing one.
  (if (nil? (@lobos.connectivity/global-connections :default-connection))
    ((lobos.connectivity/open-global db-spec) :default-connection)
    (@lobos.connectivity/global-connections :default-connection)))

(def db
  {:classname "org.postgresql.Driver"
   :subprotocol "postgresql"
   :subname "//localhost:5432/px"})

(open-global-when-necessary db)

That works fine locally, so let’s move to Heroku. To get started with Clojure on Heroku I recommend you read:

  1. Getting Started With Clojure on Heroku/Cedar
  2. Building a Database-Backed Clojure Web Application

I took the code used to extract the database specification from DATABASE_URL but I modified it so I don’t depend on that environment variable existing on my local computer and I ended up with the following config.clj:

(ns lobos.config
  (:require [clojure.string :as str] lobos.connectivity)
  (:import (java.net URI)))

(defn heroku-db
  "Generate the db map according to Heroku environment when available."
  []
  (when (System/getenv "DATABASE_URL")
    (let [url (URI. (System/getenv "DATABASE_URL"))
          host (.getHost url)
          port (if (pos? (.getPort url)) (.getPort url) 5432)
          path (.getPath url)]
      (merge
       {:subname (str "//" host ":" port path)}
       (when-let [user-info (.getUserInfo url)]
         {:user (first (str/split user-info #":"))
          :password (second (str/split user-info #":"))})))))

(defn open-global-when-necessary
  "Open a global connection only when necessary, that is, when no previous
  connection exist or when db-spec is different to the current global
  connection."
  [db-spec]
  ;; If the connection credentials has changed, close the connection.
  (when (and (@lobos.connectivity/global-connections :default-connection)
             (not= (:db-spec (@lobos.connectivity/global-connections :default-connection)) db-spec))
    (lobos.connectivity/close-global))
  ;; Open a new connection or return the existing one.
  (if (nil? (@lobos.connectivity/global-connections :default-connection))
    ((lobos.connectivity/open-global db-spec) :default-connection)
    (@lobos.connectivity/global-connections :default-connection)))

(def db
  (merge {:classname "org.postgresql.Driver"
          :subprotocol "postgresql"
          :subname "//localhost:5432/px"}
         (heroku-db)))

(open-global-when-necessary db)

After you push to Heroku, you can run heroku run lein repl, load lobos.config and run the migrations just as if they were local.

Thanks to Daniel Magliola and Nicolas Buduroi for reading drafts of this.

My first steep to borghood

image

I wish my first step to borghood was something cooler, like a laser eye, but nevertheless I’m extremely thankful to the men and women of science, and engineering, that challenged nature and decided that humans are repairable. I’m no longer 100% organic, what you see in the picture is inside of me, part of me. It’s fixing a hernia I had.

For a few hours I couldn’t move. The joy I got afterwards when I was finally able to eat soup by myself or walk around was immense. Pure happiness at the realization of how much I normally have.

I wish this perspective on life would stay with me, but I know that in two weeks I’ll be complaining about Twitter being down or some other non-issue as if it was about life and death. Not unlike all the other spoiled healthy people.

Why I love Lisp

This post was extracted from a small talk I gave at Simplificator, where I work, titled “Why I love Smalltalk and Lisp”. There’s another post titled “Why I love Smalltalk” published before this one.

Desert by Guilherme Jófili

Lisp is an old language. Very old. Today there are many Lisps and no single language is called Lisp today. Actually, there are as many Lisps as Lisp programmers. That’s because you become a Lisp programmer when you go alone in the desert and write an interpreter for your flavor of lisp with a stick on the sand.

There are two main Lisps these days: Common Lisp and Scheme, both standards with many implementations. The various Common Lisps are more or less the same, the various Schemes are the same at the basic level but then they differ, sometimes quite significantly. They are both interesting but I personally failed to make a practical use of any of those. Both bother me in different ways, and of all the other Lisps, my favorite is Clojure. I’m not going to dig into that, it’s a personal matter and it’ll take me a long time.

Clojure, like any other Lisp, has a REPL (Read Eval Print Loop) where we can write code and get it to run immediately. For example:

5
;=> 5

"Hello world"
;=> "Hello world"

Normally you get a prompt, like user>, but here I’m using the joyful Clojure example code convention. You can give this REPL thing a try and run any code from this post in Try Clojure.

We can call a function like this:

(println "Hello World")
; Hello World
;=> nil

It printed “Hello World” and returned nil. I know the parenthesis look misplaced but there’s a reason for that and you’ll notice it’s not that different from Javaish snippet:

println("Hello World")

except that Clojure uses the parenthesis in that way for all operations:

(+ 1 2)
;=> 3

In Clojure we also have vectors:

[1 2 3 4]
;=> [1 2 3 4]

symbols:

'symbol
;=> symbol

The reason for the quote is that symbols are treated as variables. Without the quote, Clojure would try to find its value. Same for lists:

'(li st)
;=> (li st)

and nested lists

'(l (i s) t)
;=> (l (i s) t)

Here’s how defining a variable and using it looks like

(def hello-world "Hello world")
;=> #'user/hello-world

hello-world
;=> "Hello world"

I’m going very fast, skipping lots of details and maybe some things are not totally correct. Bear with me, I want to get to the good stuff.

In Clojure you create functions like this:

(fn [n] (* n 2))
;=> #<user$eval1$fn__2 user$eval1$fn__2@175bc6c8>

That ugly long thing is how a compiled function is printed out. Don’t worry, it’s not something you see often. That’s a function, as created by the operator fn, of one argument, called n, that multiplies the argument by two and returns the result. In Clojure as in all Lisps, the value of the last expression of a function is returned.

If you look at how a function is called:

(println "Hello World")

you’ll notice the pattern is, open parens, function, arguments, close parens. Or saying it in another way, a list where the first item is the operator and the rest are the arguments.

Let’s call that function:

((fn [n] (* n 2)) 10)
;=> 20

What I’m doing there is defining an anonymous function and applying it immediately. Let’s give that function a name:

(def twice (fn [n] (* n 2)))
;=> #'user/twice

and then we can apply it by name:

(twice 32)
;=> 64

As you can see, functions are stored in variables like any other piece of data. Since that’s something that’s done very often, there’s a shortcut:

(defn twice [n] (* 2 n))
;=> #'user/twice

(twice 32)
;=> 64

Let’s make the function have a maximum of 100 by using an if:

(defn twice [n] (if (> n 50) 100 (* n 2))))

The if operator has three arguments, the predicate, the expresion to evaluate when the predicate is true and the one when it’s false. Maybe like this it’s easier to read:

(defn twice [n]
  (if (> n 50)
      100
      (* n 2)))

Enough basic stuff, let’s move to the fun stuff.

Let’s say you want to write Lisp backwards. The operator at the last position, like this:

(4 5 +)

Let’s call this language Psil (that’s Lisp backwards… I’m so smart). Obviously if you just try to run that it won’t work:

(4 5 +)
;=> java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)

That’s Clojure telling you that 4 is not a function (an object implementing the interface clojure.lang.IFn).

It’s easy enough to write a function that converts from Psil to Lisp:

(defn psil [exp]
  (reverse exp))

The problem is that when I try to use it, like this:

(psil (4 5 +))
;=> java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)

I obviously get an error, because before psil is called, Clojure tries to evaluate the argument, that is, (4 5 +) and that fails. We can call it explicitly turning the argument into a list, like this:

(psil '(4 5 +))
;=> (+ 5 4)

but that didn’t evaluate it, it just reversed it. Evaluating it is not that hard though:

(eval (psil '(4 5 +)))
;=> 9

You can start to see the power of Lisp. The fact that the code is just a bunch of nested lists allows you to easily generate running programs out of pieces of data.

If you don’t see it, just try doing it in your favorite language. Start with an array containing two numbers and a plus and end up with the result of adding them. You probably end up concatenating strings or doing other nasty stuff.

This way of programming is so common on Lisp that it was abstracted away in a reusable thing call macros. Macros are functions that receive the unevaluated arguments and the result is then evaluated as Lisp.

Let’s turn psil into a macro:

(defmacro psil [exp]
  (reverse exp))

The only difference is that I’m now calling defmacro instead of defn. This is quite remarkable:

(psil (4 5 +))
;=> 9

Note how the argument is not valid Clojure yet I didn’t get any error. That’s because it’s not evaluated until psil processes it. The psil macro is getting the argument as data. When you hear people say that in Lisp code is data, this is what they are talking about. It’s data you can manipulate to generate other programs. This is what allows you to invent your own programming language on top of Lisp and have any semantics you need.

There’s an operator on Clojure called macroexpand which makes a macro skip the evaluation part so you can see what’s the code that’s going to be evaluated:

(macroexpand '(psil (4 5 +)))
;=> (+ 5 4)

You can think of a macro as a function that runs at compile time. The truth is, in Lisp, compile time and run time are all mixed and you are constantly switching between the two. We can make our psil macro very verbose to see what’s going on, but before, I have to show you do.

do is a very simple operator, it takes a list of expressions and runs them one after the other but they are all grouped into one single expression that you can pass around, for example:

(do (println "Hello") (println "world"))
; Hello
; world
;=> nil

With do, we can make the macro return more than one expression and to make it verbose:

(defmacro psil [exp]
  (println "compile time")
  `(do (println "run time")
       ~(reverse exp)))

That new macro prints “compile time” and returns a do that prints
“run time” and runs exp backwards. The back-tick, ` is like the quote ' except that allows you to unquote inside it by using the tilde, ~. Don’t worry if you don’t understand that yet, let’s just run it:

(psil (4 5 +))
; compile time
; run time
;=> 9

As expected, compile time happens before runtime. If we use macroexpand things will get more clear:

(macroexpand '(psil (4 5 +)))
; compile time
;=> (do (clojure.core/println "run time") (+ 5 4))

You can see that the compile phase already happened and we got an expression that will print “run time” and then evaluate (+ 5 4). It also expanded println into its full form, clojure.core/println, but you can ignore that. When that code is evaluated at run time.

The result of the macro is essentially:

(do (println "run time")
    (+ 5 4))

and in the macro it was written like this:

`(do (println "run time")
     ~(reverse exp))

The back-tick essentially created a kind of template where the tilde marked parts for evaluating ((reverse exp)) while the rest was left at is.

There are even more surprises behind macros, but for now, it’s enough hocus pocus.

The power of this technique may not be totally apparent yet. Following my Why I love Smalltalk post, let’s imagine that Clojure didn’t come with an if, only cond. It’s not the best example in this case, but it’s simple enough.

cond is like a switch or case in other languages:

(cond (= x 0) "It's zero"
      (= x 1) "It's one"
      :else "It's something else")

Around cond we can create a function my-if straightforward enough:

(defn my-if [predicate if-true if-false]
  (cond predicate if-true
        :else if-false))

and at first it seems to work:

(my-if (= 0 0) "equals" "not-equals")
;=> "equals"
(my-if (= 0 1) "equals" "not-equals")
;=> "not-equals"

but there’s a problem. Can you spot it? my-if is evaluating all its arguments, so if we do something like this, the result is not as expected:

(my-if (= 0 0) (println "equals") (println "not-equals"))
; equals
; not-equals
;=> nil

Converting my-if into a macro:

(defmacro my-if [predicate if-true if-false]
  `(cond ~predicate ~if-true
         :else ~if-false))

solves the problem:

(my-if (= 0 0) (println "equals") (println "not-equals"))
; equals
;=> nil

This is just a glimpse into the power of macros. One very interesting case was when object oriented programming was invented (Lisp is older than that) and Lisp programmers wanted to use it.

C programmers had to invent new languages, C++ and Objective C, with their compilers. Lisp programmers created a bunch of macros, like defclass, defmethod, etc. All thanks to macros. Revolutions, in Lisp, tend to just be evolutions.

Thanks to Gonzalo Fernández, Alessandro Di Maria, Vladimir Filipović for reading drafts of this.

Openair cinema in Interlaken

image

I just watched The Blues Brothers in an open air cinema in Interlaken, Switzerland. It was a cinema built in a square on the main street. Free with a bar.

They lend blankets for you to put on the chair or cover yourself if you are cold. Some people came with their own cushions. I suppose they are regulars.

On top of that all the bar staff were dressing as the Blues brothers and so people too. Others just Blues Brothers t-shirts. During the movie people would laugh really loud, cheer, shout.

It was quite an experience.

The joyful Clojure example code convention

I started reading The Joy of Clojure, seems like a great book and I like its example code convention. I’m documenting it here because I’ll adopt it on my blog and I want to be able to link to it. I’ll call it the joyful Clojure example code convention.

A simple piece of Clojure code looks like this:

(* 2 10)

If you run it on the REPL it looks like this:

user> (* 2 10)
20

The first example, it’s just the code, with no return value, the second one, shows the return value, but when you have several lines it becomes cumbersome to copy and paste:

user> (* 2 10)
20
user> (* 2 11)
22
user> (* 2 12)
24

The Joy of Clojure code convention solves both problems by removing the prompt and leaving return values in comments:

(* 2 10)
;=> 20
(* 2 11)
;=> 22
(* 2 12)
;=> 24

Now you can copy and paste and still have the results.

If the snippet prints something, it will also be displayed but without the arrow, like this:

(println "Hello world")
; Hello world
;=> nil

Passwords

At last I find someone that shares my view on passwords:

My thinking was similar but not the same. If you make me type symbols, upercase and numbers, you slow me down and make me error prone, giving more time for other people to figure out my password. If it’s a long phrase, all lowercase, after a week of using it I’m like a machine gun typing it… trrrr… done.

These days I’m quite fast with numbers, so my passwords do include numbers. But most of the passwords I auto-generate with a program, they are long, contain lowercase, uppercase, numbers and symbols. They are a mess.

Using those beautiful passwords I discovered something interesting. Many websites can’t handle passwords longer than 20 characters. Some throw weird errors, some send you back to the original register screen without saying what’s wrong and the most problematic ones are the ones that simple truncate your password. Everything seems to be fine until you try to re-login. It’s terrible.

A little personal success

This page, my blog, pupeno.com, is now hosted on WordPress.com instead of my own server; and that’s is a little personal success. Let me explain.

I tend to be a control freak. I have my own servers. I run my own nameservers. I used to run my own mailserver but some time ago I switched to Google Apps for Domain. I used to run my blog in my own server, keeping my own set of plug ins, even modifying themes when necessary.

Last weekend I published Why I love Smalltalk and it got picked by Hacker News. That traffic killed my server. I spent the whole weekend restarting and tuning Apache. You see, I can run my own server, use Puppet, keep it clean and up to date but I’m not a sysadmin. I can pretend I am for short periods of time but I’m really just a coder. I was forced to have a crush course into server tuning and I eventually got it more or less stable. By the second wave of traffic it was not trashing anymore. I have better things to do with my time that tune a web server so I decided to move and I did it.

It is a personal success because I’m giving you up control. I can’t install whatever plug in I want now. I can’t modify themes. I’m not using my own nameservers anymore. I’m giving up control and simplifying my life when I have a natural tendency to make it more complex than it is.

At the moment, my beloved pupeno.com is not ny any of my servers. Nothing. Every service related to pupeno.com is running on third party hosted solutions. I’m letting go, sleeping better and being happier.

Only a couple of hours after I migrated my blog and went it sleep it was picked by Reddit. More than double the traffic of Hacker News (that is, Hacker News minus my server downtime) and I didn’t woke to a burning and smoking server, just an impressive traffic chart and even more comments. I’m happy.

Getting started with La Clojure on Mac OS X, a visual guide

These are instructions to get started with Clojure using IntelliJ IDEA, La Clojure and Leiningen for people that don’t know any of those tools. They are for Mac OS X but they may be adaptable to other operating systems as well.

It doesn’t expect you to know Clojure or IntelliJ IDEA. I think this might be a good way for beginners to get started (instead of Emacs for example). I been using RubyMine for quite a while and I’m happy with it. The only requirement in installing Homebrew on your mac, which you should anyway if you want to code.

Install Clojure and Leiningen using Homebrew:

brew install clojure
brew install leiningen

Download IntelliJ IDEA and install it:

Run it:

Open the preferences (⌘,) and go to the plugins section:

Download and install La Clojure plugin:

Download and install the Leiningen plugin.

Restart IntelliJ IDEA:

Create a Leiningen project:

lein new foobar
 Created new project in: /Users/pupeno/Temporary/foobar

Open the project in IntelliJ IDEA:

Now open Project Structure (⌘;) and go to SDK. If you tried to run the Clojure REPL and got the error “No jdk for module ‘foobar’”, this is what you need to do to fix it:

Click on the plus sign and add a JSDK:

The default is just fine:

And you should see something like:

Go to the project

and select the newly created 1.6 SDK:

Go to modules

open dependencies:

and add a single entry:

Use the installed Clojure from /usr/local/Cellar/clojure/1.2.1/clojure.jar:

I’m not totally sure about that step. It might be that the IntelliJ project you are creating works only on a machine where Clojure is located on the same path.

As they say… works for me! Restart IntelliJ… not sure if you’ll need to, but I needed it.

Open the project if it wasn’t open and start the Clojure REPL (⇧⌘F10), it’s in the Tools menu:

It works:

Open a file:

Type a little program, like:

(defn hello-world []
  (println "Hello world"))

Load the file on the REPL (⇧⌘L), which is in Tools → Clojure REPL:

Enjoy magnificent code completion:

and run the code:

And that’s it. Whether IntelliJ IDEA and La Clojure is a viable developing environment only time will tell.

Why I love Smalltalk

Smalltalk logo

This post was extracted from a small talk I gave at Simplificator, where I work, titled “Why I love Smalltalk and Lisp”. There should be another post, “Why I love Lisp” following this one.

After I learned my basic coding skill in more or less traditional languages, like C, C++, Python, there were four languages that really taught me something new. Those languages changed my way of thinking and even if I never use them, they were worth learning. They are:

  • Smalltalk
  • Lisp
  • Erlang
  • Haskell

You can probably add Prolog to that list, but I never learned Prolog. This post is about Smalltalk.

My goal is not to teach Smalltalk but to show things that you can do with Smalltalk that you can’t do with any other language (disclaimer: surely other languages can do it, and we’ll call them Smalltalk dialects). Nevertheless I need to show you some basics of the language to be able to show you the good stuff, so here we go, a first program:

1 + 1

That of course, evaluates to 2. If we want to store it in a variable:

m := 1 + 1

Statements are finished by a period, like this:

m := 1.
m := m + 1

In Squeak, a Smalltalk implementation, there’s an object called Transcript and you can send messages to it to be displayed on the screen. It’s more or less like a log window. It works like this:

Transcript show: 'Hello world'

and it looks like this:

Squeak transcript showing the result of Transcript show: 'Hello World'

The syntax is quite unique to Smalltalk. The message, otherwise known as “method call” in other languages, is called show: (including the colon) and it takes an argument. We can run it 10 times in a row with the following snippet:

10 timesRepeat: [
  Transcript show: 'Hello world'
]

There you can start to see how Smalltalk is special. I’m sending the message timesRepeat: to the object 10, an Integer. Doing something N times repeatedly is handled by the Integer class, which if you think about it, makes sense.

The second interesting part, is the block. The part inside squared brackets. You might thing that’s the equivalent of other language’s block syntax, like in this Java example:

for(int i=1; i<11; i++) {
  System.out.println("Hello world");
}

but Smalltalk version’s is a bit more powerful. It’s a real closure. Look at this:

t := [
  Transcript show: 'Hello world'
]

Now I have a variable named t, of type BlockClosure, and I can do anything I want with that variable. If I send it the class message it’ll return its class:

t class

and if I sed it the value message, it’ll execute and leave a “Hello World” in the transcript:

t value

Let’s see some more code. A message without any arguments:

10 printString

a message with one argument:

10 printStringBase: 2

and a message with two arguments:

10 printStringBase: 2 nDigits: 10

Isn’t it cute? That method is called printStringBase:nDigits:. I never seen that syntax anywhere else; well, except in Objective-C, which copied it from Smalltalk.

Enough toying around, let’s start building serious stuff. Let’s create a class:

Object subclass: #MyClass
       instanceVariableNames: ''
       classVariableNames: ''
       poolDictionaries: ''
       category: 'Pupeno'

Notice that a class is created by sending a message to another class telling it to subclass itself with the name and a few other arguments. It’s a message, a method call like any other. Object is a class, classes are objects. The object model of Smalltalk is a beauty but that’s a subject for another post.

Now that we have a class, let’s create a method called greet: in that class.

greet: name
  "Greets the user named name"

  | message |

  message := 'Hello ', name.
  Transcript show: message.

In that method definition first we have a comment for the method, then the list of local variables within pipes (“|”), and then the implementation, which sets the variable message to contain “Hello ” and the comma concatenates name to it. Then we just send it to the transcript.

It looks like this:

MyClass greet method

Ok, let’s use it:

m := MyClass new.
m greet: 'Pupeno'

To create an object of class MyClass, we send the new message to that class. There’s no new keyword like in Java. new is just a method. You can read its code, override it, etc. Don’t mess with it unless you really know what you are doing.

Actually, if you think about it, we haven’t seen a single keyword. Look all the code we wrote without having to memorize any keywords! What’s even more important is that by now you essentially know Smalltalk. That’s all there is, but like LEGO bricks, this simple and small building blocks allow you to build whatever you want.

Yes, that’s it, that’s all there is to it. We already saw that Smalltalk doesn’t need loops, it has integers and that class implements the timesRepeat: message which allows you to do something N times. There are many other looping methods here and there.

What about the if keyword you ask? Surely Smalltalk has an if? Well, no, it doesn’t. What you can recognize as an if is actually implemented in Smalltalk using the same mechanism of classes and message passing you saw already. Just for fun let’s re-implement it.

We starte by creating the class PBoolean and then two classes inheriting from it, PTrue and PFalse.

Object subclass: #PBoolean
       instanceVariableNames: ''
       classVariableNames: ''
       poolDictionaries: ''
       category: 'Pupeno'

PBoolean subclass: #PTrue
       instanceVariableNames: ''
       classVariableNames: ''
       poolDictionaries: ''
       category: 'Pupeno'

PBoolean subclass: #PFalse
       instanceVariableNames: ''
       classVariableNames: ''
       poolDictionaries: ''
       category: 'Pupeno'

For the class we created before, MyClass, we define a equals: method that will return either true or false, or rather, PTrue or PFalse.

equals: other
  ^ PTrue new

The little hat, ^, means return. For now, just a hardcoded true. Now we can do this in the workspace:

m1 := MyClass new.
m2 := MyClass new.
m1 equals: m2

and get true, that is PTrue, as a result. We are getting close but no if yet. How should if look like? It’ll look like something like this:

m1 := MyClass new.
m2 := MyClass new.
(m1 equals: m2) ifTrue: [
  Transcript show: 'They are equal'; cr
] else: [
  Transcript show: 'They are false'; cr
]

and you can start to imagine how to implement it. In PTrue we add the method:

ifTrue: do else: notdo
  ^ do value

That method basically takes two parameters, evaluates the first one and ignores the second one. For PFalse we create the oposite:

ifTrue: notdo else: do
  ^ do value

and that’s it. A working if! If you ask me, I think this is truly amazing. And if you check Squeak itself, you’ll find the if is actually implemented this way:

True's ifTrue:ifFalse:

If your programming language allows you to create something as basic as the if conditional, then it allows you to create anything you want.

Post Navigation

Follow

Get every new post delivered to your Inbox.

Join 329 other followers