Monday, February 27, 2012

My workflow is generally
  • git checkout -b topic
  • Work on code, committing at various times.
  • Run automated tests. Go back to working on code if a test fails.
  • git rebase -i master to squash related commits.
  • git checkout master
  • git pull
  • git rebase master topic
  • Fix merge conflicts
  • Run automated tests. Go back to working on code if a test fails.
  • git checkout master
  • git merge topic
  • git branch -d topic
  • git push If this fails, go back to git pull, except working in the master branch rather than the topic branch.
And I do this from a shell within emacs. For the longest time, if I really wanted to do the git rebase -i, I'd open a new window and do the rebasing in vi, so I generally skipped that step and just had a bunch of commits with identical log messages sometimes interleaved with other commits. But then I figured that was just dumb and changed my .emacs file for the first time in over 5 years, adding
(setenv "EDITOR" "/usr/bin/emacsclient")
(server-start)

Monday, May 23, 2011

I was writing some Haskell code where I was constructing a value with lots of record fields, but only cared about one of them initially.

data Type = Type { field1 :: Type1, field2 :: Type2 }

But, omitting the irrelevant fields from the initializer causes a big "Fields not initialised" warning.

So, I figured that, instead of writing out

Type { field1 = value, field2 = undefined }

which was verbose, or

Type { field1 = value }

which resulted in the big warning, I could use

undefined { field1 = value }

which did eliminate the warning.

However,

field1 (undefined { field1 = value })

resulted in an exception. I had expected it to be equivalent to

field1 (Type { field1 = value, field2 = field2 undefined })

but it's not. Since types can have multiple constructors, it's actually equivalent to

field1 (case undefined of { Type { field2 = field2 } -> Type { field1 = value, field2 = field2 })

according to section 3.16.3 in the Haskell report.

Monday, May 9, 2011

While trying to write concurrent code that forks off threads that sleep before doing some delayed actions using GHCi, version 6.10.4, which is a pretty old version, I found some strange behavior. I used map (flip addUTCTime time) [1..5] to generate the times that the delayed actions should be performed, and the interpreter would lock up. When I changed it to map (flip addUTCTime time) [1,2,3,4,5], everything worked as expected. Maybe there is something tricky in the implementation of enumFromTo :: NominalDiffTime -> NominalDiffTime -> [NominalDiffTime]

Monday, April 25, 2011

I started using Control.Concurrent to write concurrent code in Haskell. It's easier than Java's concurrency model, since values are immutable in Haskell, while one has to worry about values being changed by other threads in Java, which means having to use locks in the right places, and knowing how to use the java.util.concurrent classes.

Of course, it's still possible to deadlock in Haskell, such as with do { a <- takeMVar ma; b <- readMVar mb; putMVar ma a } and do { b <- takeMVar mb; a <- readMVar ma; putMVar mb b }.

Also, there is no getting around dealing with external concurrency issues, such as with databases.

Monday, April 11, 2011

Thinking about real numbers in the 01_ programming language, the fractional part can be represented as big endian base 1/2. (Or is it little endian? Bits to the left represent larger numbers, but smaller powers of 1/2.) Infinite lists of bits can represent numbers that are ≥ 0 and ≤ 1.

Addition of fractional numbers can be defined as

+/fractional 0a 0b = +/fractional/carry a b 0_ 1_ +/fractional a b.
+/fractional 1a 0b = +/fractional/carry a b 1_ 0_ +/fractional a b.
+/fractional 0a 1b = +/fractional/carry a b 1_ 0_ +/fractional a b.
+/fractional 1a 1b = +/fractional/carry a b 0_ 1_ +/fractional a b.

where evaluating the carry of fractional addition is

+/fractional/carry 0a 0b carry-zero carry-one = carry-zero.
+/fractional/carry 1a 0b carry-zero carry-one = +/fractional/carry a b carry-zero carry-one.
+/fractional/carry 0a 1b carry-zero carry-one = +/fractional/carry a b carry-zero carry-one.
+/fractional/carry 1a 1b carry-zero carry-one = carry-one.

And the subtraction of fractional numbers is

-/fractional 0a 0b = -/fractional/borrow a b 0_ 1_ -/fractional a b.
-/fractional 1a 0b = -/fractional/borrow a b 1_ 0_ -/fractional a b.
-/fractional 0a 1b = -/fractional/borrow a b 1_ 0_ -/fractional a b.
-/fractional 1a 1b = -/fractional/borrow a b 0_ 1_ -/fractional a b.

where evaluating the borrow of fractional subtraction is

-/fractional/borrow 0a 0b borrow-zero borrow-one = -/fractional/borrow a b borrow-zero borrow-one.
-/fractional/borrow 1a 0b borrow-zero borrow-one = borrow-zero.
-/fractional/borrow 0a 1b borrow-zero borrow-one = borrow-one.
-/fractional/borrow 1a 1b borrow-zero borrow-one = -/fractional/borrow a b borrow-zero borrow-one.

Unlike the addition and subtraction of integers, these operations, in general, require infinite time and memory to calculate a finite number of bits, due to the carry and borrow.

Monday, March 28, 2011

Thinking about numbers in the 01_ programming language, the natural way to represent integers would be to use little-endian base 2. To further simplify things, consider only infinite lists of bits. So the important numbers are

zero = 0 zero.
one = 1 zero.

Negative numbers can also be represented

-one = 1 -one.

Integer addition can be defined as

+/integer 0a 0b = 0 +/integer a b.
+/integer 1a 0b = 1 +/integer a b.
+/integer 0a 1b = 1 +/integer a b.
+/integer 1a 1b = 0 +/integer/carry a b.

where integer addition with carry is

+/integer/carry 0a 0b = 1 +/integer a b.
+/integer/carry 1a 0b = 0 +/integer/carry a b.
+/integer/carry 0a 1b = 0 +/integer/carry a b.
+/integer/carry 1a 1b = 1 +/integer/carry a b.

And integer subtraction is

-/integer 0a 0b = 0 -/integer a b.
-/integer 1a 0b = 1 -/integer a b.
-/integer 0a 1b = 1 -/integer/borrow a b.
-/integer 1a 1b = 0 -/integer a b.

where integer subtraction with borrow is

-/integer/borrow 0a 0b = 1 -/integer/borrow a b.
-/integer/borrow 1a 0b = 0 -/integer a b.
-/integer/borrow 0a 1b = 0 -/integer/borrow a b.
-/integer/borrow 1a 1b = 1 -/integer/borrow a b.

Monday, March 14, 2011

For work, some of the code is in JSTL (JavaServer Pages Standard Template Library) EL (Expression Language). JSTL EL is weakly typed and dynamically typed. There is no compile-time checking.

One day, a coworker sent me a message saying some stuff stopped working after merging in some of my changes. So I tried running it and it didn't work. I also added logging to the code I changed, which was all Java, and it was working fine. I then tracked it down to some JSTL (untouched by me):

<c:set var="flag" value="{flag1 || flag2}"/>
...
<c:if test="${flag}">
... stuff that failed to appear ...
</c:if>

The first line should have been

<c:set var="flag" value="${flag1 || flag2}"/>

This is the type of stupid mistake that compile-time checking, especially with static typing, can catch.