Archive | C99 RSS for this section

Again, This Time In Reverse!

Today we’ll be doing Exercise 5 from The C Programming Language. Today’s exercises aren’t terribly challenging, but there is some good stuff in here. The problem is:

Modify the temperature conversion program to print the table in reverse order, that is, from 300 degrees to 0.

I bet you thought we were done with temperature conversion, didn’t you? I’m right there with you, but luckily for us, this is also the section that introduces the for loop, so this is much less tedious. The new program for modification:

#include <stdio.h> int main (int argc, char ** argv) { for (int fahr = 0; fahr <= 300; fahr = fahr + 20) { printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32)); } }

I made a few minor modifications. I gave main the correct signature to keep gcc from complaining, and I also moved the initialization of fahr to the loop. As you may know this is not valid C, and the compiler will throw an error. You might also know that this was made to be valid C in the C 99 revision. To compile this, you just need to add the -std=c99 flag to your gcc call.

To complete this exercise, you only need to modify the loop declaration. Change this line…

for (int fahr = 0; fahr <= 300; fahr = fahr + 20)

…to this…

for (int fahr = 300; fahr >= 0; fahr = fahr - 20)

Pretty straight forward stuff here. fahr starts at 300 instead of 0, and the loop continues so long as it remains greater than 0. Instead of adding 20 each iteration, we subtract it. This can be compiled like so:

gcc -std=c99 -Wall ex5.c -o ex5

In Haskell

Unfortunately, the authors of The C Programming Language did not see fit to include a starting Haskell program for us to modify. This seems like a pretty serious oversight to me, but we’ll just have to make due. Luckily for us, we can use the temperature conversion program I wrote for the last entry in this series. This program handles conversions, and we can use it to produce a table of all conversions between 0 and 300 degrees.

While I’ve established that Haskell does in fact have loops, we won’t be using them here. Instead we’ll be using ranges, functors, and sequencing to solve this problem in a more functional way.

First, we need a list of every 20th number between 0 and 300:

[300.0, 280.0 .. 0.0]

The .. there basically says “You get the idea, do that.” If you put enough information into it so that the compiler can figure out the pattern, and start and end points, the compiler will fill the rest in. In this case, I gave the first two values, telling the compiler I want increments of 20, and I gave it the last value so it knows where to stop.

Unfortunately, as you recall, my conversion program needs members of the Temperature typeclass. Surely I don’t plan to make Double a member, right? Right. We need to map a function over this list to produce a list of Temperatures. But what function should we use?

Something that beginning Haskellers may not realize is that constructors are in fact functions!

Prelude> :t Just Just :: a -> Maybe a Prelude> :t Left Left :: a -> Either a b

…and of course…

*Main> :t Fahrenheit Fahrenheit :: Double -> Fahrenheit

That’s right, we can map Fahrenheit over a functor just like any other function!

map Fahrenheit [300.0, 280.0 .. 0.0]

This will produce a list of every 20th Fahrenheit temperature between 300 and 0. However, we aren’t done yet. We actually need a list of Conversions, because this type is required for our insertConv function. To get this we can map toConversion over this list:

map toConversion $ map Fahrenheit [300.0, 280.0 .. 0.0]

…but that’s starting to get a bit ugly, there must be a better way. Normally, I’m not terribly fond of function composition, in this case it will make our life easier.

Function Composition

Haskell provides an operator . that is used for function composition. Let’s take a look at its type:

Prelude> :t (.) (.) :: (b -> c) -> (a -> b) -> a -> c

The composition operator takes a function that takes some type b as an argument, and that returns some type c. It takes a second function that takes some type a as an argument, and that returns some type b. Finally, it returns some type c.

What does this do for us? Basically, it takes a function a -> b, and a function b -> c, and turns them into a function a -> c. Let’s see an example:

Prelude> :t show show :: Show a => a -> String

The function show takes a member of the Show typeclass and returns a String.

Prelude> :t putStr putStr :: String -> IO ()

The function putStr takes a String, and returns an IO action.

Prelude> :t putStr . show putStr . show :: Show a => a -> IO ()

When we compose the two functions, we get a function that takes a member of the Show typeclass, and returns an IO action.

Logically, calling putStr . show someShowable is the same as calling putStr $ show someShowable or putStr (show someShowable). However, putStr . show is a valid function, where putStr $ show and putStr (show) are compiler errors if you don’t give show an argument.

How does this help us?

*Main> :t Fahrenheit Fahrenheit :: Double -> Fahrenheit *Main> :t toConversion toConversion :: (Temperature a, Temperature b) => a -> (a, b) *Main> :t toConversion . Fahrenheit toConversion . Fahrenheit :: Temperature b => Double -> (Fahrenheit, b)

By composing toConversion and Fahrenheit, we end up with a function that takes a Double as an argument and returns a Conversion from Fahrenheit. We can then map this function over our list of Doubles:

map (toConversion . Fahrenheit) [300.0, 280.0 .. 0.0]

Next, we need to turn these Conversions into TableBuilders. This is a simple matter of composing insertConv:

map (insertConv . toConversion . Fahrenheit) [300.0, 280.0 .. 0.0]

The type of this new function is:

:t (insertConv . toConversion . Fahrenheit) (insertConv . toConversion . Fahrenheit) :: Double -> TableBuilder ()

…or at least it would be if the type inferrer could figure out the type of toConversion. Unfortunately for us, it can’t because the implementation is purposely ambiguous. We need to add a type signature to it:

(insertConv . (toConversion :: Fahrenheit -> (Fahrenheit, Celsius)) . Fahrenheit)

Sequencing

Now we are ready to create our table. This part is actually very easy. Thanks to the library function sequence_ we won’t even need a do block. What does this function do? Let’s look at its signature:

Prelude> :t sequence_ sequence_ :: Monad m => [m a] -> m () Prelude> :t sequence sequence :: Monad m => [m a] -> m [a]

There are two variations of this function. The first, sequence_ evaluates each monadic action, and ignores the results. Basically, suppose we have some function: func :: a -> Monad b

let mList = map func ["foo", "bar", "baz"] in sequence_ mList

…is equivalent to…

do func "foo" func "bar" func "baz" return ()

The second variation evaluates each monadic action, and returns a list of all the results. Suppose we have our same function: func :: a -> Monad b

let mList = map func ["foo", "bar", "baz"] in sequence mList

…is equivalent to…

do foo <- func "foo" bar <- func "bar" baz <- func "baz" return [foo, bar, baz]

If you have a list of monads, you can use sequence or sequence_ to have them all evaluated. Use sequence if you care about the resulting values, use sequence_ if you only care about the monad’s side effect. Which do we want? Let’s look at the signature of insertConv:

*Main> :t insertConv insertConv :: (Temperature a, Temperature b) => Conversion a b -> TableBuilder ()

If we were to use sequence, we’d get a resulting value with the type TableBuilder [()]. Since nobody has any use for a list of empty tuples, we’ll be using sequence_.

So, what does our main look like?

main = do temps <- return (map (insertConv . (toConversion :: Fahrenheit -> (Fahrenheit, Celsius)) . Fahrenheit) [300.0, 280.0 .. 0.0]) putStrLn $ prettyPrint $ buildTable $ do sequence_ temps

This produces the following output:

------------------------------ || Fahrenheit || Celsius || ------------------------------ || 300.0 |> 148.9 || || 280.0 |> 137.8 || || 260.0 |> 126.7 || || 240.0 |> 115.6 || || 220.0 |> 104.4 || || 200.0 |> 93.3 || || 180.0 |> 82.2 || || 160.0 |> 71.1 || || 140.0 |> 60.0 || || 120.0 |> 48.9 || || 100.0 |> 37.8 || || 80.0 |> 26.7 || || 60.0 |> 15.6 || || 40.0 |> 4.4 || || 20.0 |> -6.7 || || 0.0 |> -17.8 || ------------------------------

DMP Photo Booth: Going All In With GLib Primitives

While working on DMP Photo Booth, I’ve been trying to use GLib library calls as often as possible as opposed to standard library calls. Why? Portability, of course. I’ve been doing my best to ensure my application is as portable as possible. While doing this, I find myself having to work with lots of glib types. After a few weeks of this, I find myself wondering if I shouldn’t be using these in my own code…

GLib Primitives

GLib defines g[type] versions of all standard C primitives, plus a few extras. The GLib reference manual describes these as falling into 4 different categories:

  • New types which are not part of standard C (but are defined in various C standard library header files) – gboolean, gsize, gssize, goffset, gintptr, guintptr.
  • Integer types which are guaranteed to be the same size across all platforms – gint8, guint8, gint16, guint16, gint32, guint32, gint64, guint64.
  • Types which are easier to use than their standard C counterparts – gpointer, gconstpointer, guchar, guint, gushort, gulong.
  • Types which correspond exactly to standard C types, but are included for completeness – gchar, gint, gshort, glong, gfloat, gdouble.

Let’s talk about these.

New Types

The new types represent boolean values, and size types. Both of these may have been new when GLib defined them, but they’ve since found their way into the C standard library since C99. That said, these are types that we often neglect to use. Who can honestly say they’ve never used a bare integer when a size_t would have been appropriate?

I feel that these are all good types to use, when needed. Maybe they no longer solve a real problem since C99, but GLib still uses them. I will use these for consistency’s sake, but the standard library types should suffice.

Integer Types

As we should all know, integers are not guaranteed to be the same size across different platforms. On platform A, an int may be 2 bytes, and on platform B, it may be 4 bytes. Meanwhile, these types provide this guarantee. Like the new types, C99 brings these types also, but in my opinion gint8 is easier to type than int_8.

Aside from ease, GLib uses its types, and for consistency I will too.

Types That Are “Easier To Use”

In my opinion, this one is debatable. The people over at Gnome may think that gpointer “looks better” and is “easier to use”, but I find it incredibly confusing. I’ve even mentioned this in past posts. Gpointer is a typedef of void *. In other words, where you may have done this before:

void * foo = malloc(sizeof(foo));

…you would now do this:

gpointer foo = g_malloc(sizeof(foo))

…and now you’re left with this gpointer foo;. Aside from the fact that it has the word “pointer” in the type name, this doesn’t look like a pointer. Even worse is when you see gpointer * bar;. At first glance, this looks like it should be a void * bar;, but it’s actually void * * bar;. I know I’ve spent more time than I care to admit trying to figure out why bar->the_bar was throwing compiler errors.

Maybe it’s just amateur hour in the DMP Undersea Laboratory, but I like to see the *. That way it’s right in my face that I’m dealing with a pointer. I can also count the number of *s to see how many array indices I’m dealing with. If I see void *** super_foo; I know I’m dealing with a 3 dimensional array just by counting the stars. I don’t have to think about it. On the other hand if I see gpointer ** super_foo; I have to know what gpointer is a typedef of; I can’t just trust my instincts.

For this reason, I will not be using gpointer or gconstpointer. The rest of the “easier to use” types can stay though.

Types That Correspond Exactly

There is not much to say about these. These types exist just for consistency’s sake. If you’re using GLib primitives, you should use these as well for consistency’s sake.

Seems Kind Of Pointless…

At first glance, yes it does. I must admit that while I was typeing this up, I wavered. “If all the GLib types are in the standard library in C99, why bother?” I thought. None of these types are objectivly better than the standard library versions, it’s just another name to remember. So why should we care?

The answer is because not all compilers/platforms support C99. The most nobale offender here is Microsoft Visual Studio. To quote Herb Sutter: “Our primary goal is to support “most of C99/C11 that is a subset of ISO C++98/C++11.”” This allegedly includes “C99 preprocessor and library extensions”, but this requires compiling with Visual Studio’s C++ compiler and accepting all the baggage that C++ brings. If you want to keep your code pure C, then you are stuck using C90 only.

So, long story short: if you want easy portability to Windows, consider using GLib primitives.

Moving Forward

It is time to get with the program. Development of DMP Photo Booth is still early-enough along that a refactor to use GLib primitives won’t be too difficult. I will not change the API for the modules because, while I will most likely use GLib with the reference modules, I don’t want to impose a requirement to use GLib. Int and char are exactly equivilent to gint and gchar, so this should not cause any issues.

However, moving forward, I’ll be using GLib primitives.

%d bloggers like this: