8
\$\begingroup\$

After reading this question, I've realized that I can do a lot to improve the quality of my question, so I've edited this question quite a bit.

I've been teaching myself F# in my spare time off and on for the last 6 months. I've finally started getting comfortable enough with the language to feel that a lot of my code could be much better. The problem is, I don't know what changes to make.

Here's what I'm interested in:

  • I'm using higher order functions to return functions for interacting with a specific message queue. Is this a good design. Would another F# developer feel comfortable with this?
  • Does this fit the idiomatic style of F#?
  • If you know RabbitMQ, are there any bugs which I may be creating here.

Here's the context of the little block of code:

I'm doing a lot of experiments with messaging systems and I've been using RabbitMQ as a messaging framework. There's a .Net library for RabbitMQ but it's written in and for C#. I can use it in F# but it feels clunky. I wanted a small wrapper around the RabbitMQ library which which convert it into a more functional interface. Also, this will hopefully make it very easy to use RabbitMQ in an F# program.

My wrapper handles the following for RabbitMQ:

  1. Connect to a RabbitMQ server
  2. Create a function which will let you read one message from a queue
  3. Create a function which will write a message to a queue
  4. For both 2 and 3, if the queue doesn't exist, the queue will be created (that's the declareQueue)

    module Client =
     let connectToRabbitMqServerAt address = 
     let factory = new ConnectionFactory(HostName = address)
     factory.CreateConnection()
     let openChannelOn (connection:IConnection) = connection.CreateModel()
     let private declareQueue (channel:IModel) queueName = 
     channel.QueueDeclare( queueName, false, false, false, null )
     let private publishToQueue (channel:IModel) queueName (message:string) =
     let body = Encoding.UTF8.GetBytes(message)
     channel.BasicPublish("", queueName, null, body)
     let createQueueReader channel queue = 
     declareQueue channel queue |> ignore
     fun () -> 
     let ea = channel.BasicGet(queue, true)
     if ea <> null then
     let body = ea.Body
     let message = Encoding.UTF8.GetString(body)
     Some message
     else
     None
     let createQueueWriter channel queue =
     declareQueue channel queue |> ignore
     publishToQueue channel queue
    

An example use case would be:

// open a connection to a RabbitMQ broker
let connection = connectToRabbitMqServerAt "localhost"
let myChannel = openChannelOn connection
// Connect to a queue for writing
let writeToHelloQueue = createQueueWriter myChannel "hello"
// write the message "Hello, World" to the queue "hello"
"Hello, World" |> writeToHelloQueue
asked Mar 9, 2014 at 19:03
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Overall, this code looks very good. Just two nitpicks here:

  1. Give your function definitions lines to themselves:
let openChannelOn (connection:IConnection) = connection.CreateModel()
  1. Use match statements unless you are checking a boolean value directly:
if ea <> null then
 let body = ea.Body
 let message = Encoding.UTF8.GetString(body)
 Some message
else
 None

Becomes:

match ea with
| null -> None
| _ ->
 let body = ea.Body
 let message = Encoding.UTF8.GetString(body)
 Some message
answered Dec 31, 2016 at 16:56
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.