2012-04-30

ANN: hflags-0.1 released

HFlags is library for making it easier to specify and use command line flags in Haskell programs and libraries. It is very similar in its concepts to Google's gflags library.

TL;DR

Example:

#!/usr/bin/env runhaskell

{-# LANGUAGE TemplateHaskell #-}

import HFlags

defineFlag "name" "Indiana Jones" "Who to greet."
defineFlag "r:repeat" (3 + 4 :: Int)
  "Number of times to repeat the message."

main = do remainingArgs <- $(initHFlags "Simple program v0.1")
          sequence_ $ replicate flags_repeat greet
  where
    greet = putStrLn $ "Hello "
                       ++ flags_name
                       ++ ", very nice to meet you!"

Code: https://github.com/errge/hflags
Docs: http://hackage.haskell.org/packages/archive/hflags/latest/doc/html/HFlags.html
More examples: https://github.com/errge/hflags/tree/master/examples

There are a tons of flags libraries already for Haskell, aren't there?

Yes, but none like gflags! All of them are like getopt. Some has fancy Template Haskell automation, some not, but in general, they are all the same. If you want to look into some, I recommend CmdArgs and options.

Some properties of getopt like libraries, that I don't like:

  • You can only access the flags in the IO monad. This seems to be reasonable, at least at first look. Flags originate from the environment, and accessing the environment is only safe through IO, right? But in my opinion, they are more similar to constants, they should be easy to use everywhere.
  • You have to pass the flags to every function where you want to use them. This is also something, that is not true for simple top level constants, why should flags behave differently?
  • Getopt makes it very hard to compose different code parts (e.g. libraries) that all use command line flags. Imagine, that you are implementing a sendmail library, which will use the default /usr/bin/sendmail executable on the system, but gives the user the flexibility to change the path via command line flags. This can be done via getopt like thinking, but it requires a lot of boilerplate in the program using your library (for an example, have a look on option's import feature and imagine doing that for all of the libs you use). Gflags solved this issue very nicely for C++/Java/Python, but there were no similar solution to Haskell.

HFlags tries to get rid of these properties and be as simple and easy to use as possible.

gflags C++ example

As a motivation for HFlags, let's have a look on Google's C++ example:

#include <gflags/gflags.h>

DEFINE_bool(big_menu, true,
            "Include 'advanced' options in the menu listing");
DEFINE_string(languages, "english,french,german",
              "comma-separated list of languages to offer");

...

int main(int argc, char **argv) {
   google::ParseCommandLineFlags(&argc, &argv, true);
   ...
   if (FLAGS_big_menu) { ... }
   ...
}

Note, that once you called google::ParseCommandLineFlags you're done. All of the flags in every linked in C++ file gets initialized by that call and you can access all of the flags in every file (where they are declared) via top level, global names.

Achieve the same in Haskell

It was a long journey to achieve this kind of comfort in Haskell, in a later post I'll do a code walk around HFlags.hs, but it's already well commented and should be understandable for anyone who is familiar with type classes, instances and a little bit of Template Haskell. Instead, let's concentrate usage for now!

If you decide to give it a try, all you have to do is to cabal install hflags, then import HFlags in your source files where you define flags and in your main. After that, you can use defineFlag for flags with type of Bool, Double, Int, Integer and String. If you need other types, you can look into defineQQFlag and defineCustomFlag.

The last step is to make sure that you call initHFlags as the first thing in your main.

If you are not up to coding right now, have a look at the simple and the complex example. If you can't believe that we can expose the flags in all the imported modules automatically and you need a demonstration, look into ImportExample.hs.

Some criticism, we already heard

Fake pureness and usage of unsafePerformIO is bad!

The criticism goes like this: “This library is not pure, you are using unsafePerformIO. This is unsafe, it's in its name. I don't know what does that mean, but it can't be good, it's unsafe. So unsafe. Are you sure that this is OK?”

TL;DR: yes, we are sure, kind of.

Longer version: there are two uses of unsafePerformIO in our code, one is trivial and well known, the other is a bit more tricky.

The simple one is responsible for the creation of the global IORef, holding the Map that maps flag names to values. Here, we used the standard way to create a top level mutable variable, as discussed in the wiki.

The other one is when you define flag foobar, we create a top level constant with the name flags_foobar containing the value. This is not a top level mutable variable, but a constant, so the wiki page doesn't apply. The usage of unsafePerformIO means that you can be afraid of that these constants are not really constant and they change randomly (depending on evaluation order, environment, state of the moon) and not at all referentially transparent anymore.

To address this concern, we force evaluate all of these top level constants at initHFlags time, so the thunk containing unsafePerformIO gets evaluated in them and they become real constants. We generate a NOINLINE pragma for them, so they won't be duplicated (and actually that wouldn't cause any issue either).

If you are interested to read more about these issues and other real world issues in Haskell, I strongly recommend reading the very well written Tackling the Awkward Squad from Simon Peyton Jones.

We are aware of these dangers, but we think that a trade-off had to be cut to make command line flags usable, easy to manage and fun to have. If you don't agree with the necessity of these considerations and you believe only in totally pure solutions, this library is not for you.

Also, we are not experts on this topic, so if you still think that we made an error somewhere and you can come up with some real example, where our library screws up your program, definitely leave a comment!

Programs using this library will be hard to test!

If you're unittesting some code where the behavior can be seriously changed via command line flags then this library is probably not your biggest concern. Those things should be system (functional) tested, where specifying flags is totally normal.

BTW, have you heard of withArgs?

Comments are welcome!

View from Thalwil train station

8 comments:

  1. We're very nice full for your diary post. You'll realize plenty of approaches once visiting your post. Good think. www.health-journal.hu

    ReplyDelete
  2. The Ultimate Guide to the Casino in NJ - DRMCD
    The 청주 출장마사지 first part of this article is just a few tips and 사천 출장안마 tricks, along with 광주광역 출장마사지 useful tips for casino operators. We are going 구리 출장샵 to be 광양 출장마사지 talking about the

    ReplyDelete

  3. Hacking is not an easy task and not everyone can do this, but in some minor cases if you to learn como intervenir un telefono than this place if for youthebuyingpro.com. By reading this useful article you can easily learn that how to hack anyone phone.

    ReplyDelete
  4. The standard roulette table employs up to as} 10 sets of wheel checks . Each set is a unique way|in one other way} colored; each historically consists of 300 chips; and there is be} one set for each player. The chips usually have a single basic value, although some casinos additionally promote chips of lesser 카지노사이트.online value.

    ReplyDelete
  5. All staff at Fabrication Designs, Inc. take satisfaction of their personal contribution and assure that you may be} protected by our merchandise. Shade constructions, pergolas, entry features, stairways, boardwalks, indicators, profile cut Corten, aluminum, stainless steel, and painted metal panels. We excel working with architects to supply all kinds of features that additional enhance the attraction of your park or gathering area. We construct freeway bridges best plungers consisting of welded wide flange beams, rolled girders, and welded field girders.

    ReplyDelete
  6. Even if a nonplayer sits down when only one participant is at the table, the dealer will ask the nonplayer to maneuver. A few French wheels are in use within the United States mostly in high-limit 코인카지노 rooms. They often carry larger minimal bets than American wheels -- but a participant in these areas who plans to make larger bets and desires to play roulette ought to seek out a French wheel.

    ReplyDelete
  7. If you're a new casino player, we would definitely 먹튀검증 recommend 3-reel slot video games. Random Number Generator is a computer element and it is built-in into all video slots. This system has one necessary function – to create hundreds of thousands of various sequences throughout the day. All numbers created by this program are random, with a special collection of determiners every time a customer spins the slot.

    ReplyDelete
  8. Because these games are hosted by skilled dealers who use state-of-the-art tools, you will have have} the possibility to take pleasure in a practical gaming expertise that's as entertaining as it is rewarding. These games are streamed using HD cameras and can be loved on a variety of|quite a lot of|a wide range of} units 24/7. And what makes them even better is that the maximum desk limits are sometimes pretty high, making them good for high-roller on line casino gamers. However, it turned easy to 코인카지노 see why many roulette gamers have chosen this as their go-to website for cell roulette the extra we explored the app using a spread of different units. When it involves no-deposit bonuses, it’s worth noting that from time to time this on line casino might email special XBet no-deposit bonus codes to its existing gamers. So, make sure that you|just keep in mind to|just make sure you} opt-in to obtain promotional notifications to keep away from missing out.

    ReplyDelete