Skip to content

Instantly share code, notes, and snippets.

@schweigert
Last active March 17, 2024 01:46
Show Gist options
  • Star 61 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save schweigert/385cd8e2267140674b6c4818d8f0c373 to your computer and use it in GitHub Desktop.
Save schweigert/385cd8e2267140674b6c4818d8f0c373 to your computer and use it in GitHub Desktop.
Embedding GoLang into a Ruby application - Blogpost to Magrathealabs

Go Title

I am passionate about Ruby, but its execution time compared to other languages is extremely high, especially when we want to use more complex algorithms. In general, data structures in interpreted languages become incredibly slow compared to compiled languages. Some algorithms such as ´n-body´ and ´fannkuch-redux´ can be up to 30 times slower in Ruby than Go. This is one of the reasons I was interested in embedding Go code in a Ruby environment.

For those who do not know how shared libraries operate, they work in a similar way as DLLs in Windows. However, they have a native code with a direct interface to the C compiler.

Note Windows uses the DLL system, and in this case, this does not necessarily have to be in native code.

One example is DLLs written in C#, which runs on a virtual machine. Because I do not use windows, I ended up not testing if it is possible to perform these steps on it.

You need Golang 1.5 or higher and Ruby 1.8.7 or higher.

1. Create your Go library!

It would be like any library, but it must have some peculiar characteristics.

Use C language types

For signing external functions to your library, you will need to use the C language typing. For the rest of the code, you can convert to the standard Go typing.

To do this include library:

import "C"

Remember that this is the Achilles' heel of Go Lang.

It's a shit

Try to generate a small interface, where only few data is carried on. In general, data type translation is extremely slow when converting from Go to C types!

Function export signature

You need to tell the Go compiler which functions will be public in the library by adding a comment above your function:

import "C"

//export my_add
func my_add(a, b C.int) C.int {
   return a + b
}


func main() {
// This is necessary for the compiler.
// You can add something that will be executed when engaging your library to the interpreter.
}

Remember that the exported functions must be in your main package.

Note I know that the standard of nomenclatures in Go is different from what we found in this example, but I've created the habit of writing interfaces using the Ruby style. For this reason, the names of the functions are written using snake_case and not camelCase.

Compile

Just type:

  go build -o my_lib.so -buildmode=c-shared my_file.go

Writing the interface with the shared library in Ruby

This is the fastest way to embed Go code into a Ruby environment, however, remember that in this way the call time of the go interface will not be so fast.

Preparing the environment

Add to your Gemfile the following gem:

  gem 'ffi'

Or of course, manually install it: gem install ffi

Create a module for your library

Just create a module and write your function signatures inside the Ruby package. This is like a .h file:

require 'ffi'

module Foo
  extend FFI::Library
  ffi_lib './my_lib.so'

  attach_function :my_add, [:int, :int], :int
end

puts Foo.my_add(2, 2)
# => 4

What I noticed by running native Go code in the Ruby environment?

Integrating Go and Ruby is fast and efficient for certain situations. Running the native code in Go brings several advantages, bringing you various graphical, database and efficient data structures libraries already implemented in Go and the efficiency of Go routines.

Remember that this applies when we use little data translations between Ruby and Go. This will only be advantageous if you have a huge real gain like the algorithms I quoted above, ´n-body´ and ´fannkuch-redux´, offsetting this loss by calling a function through the Go C Library.

@MichaelCurrin
Copy link

This looks a like a good case for a blog post like on dev.to

BTW you step 1. ... and no step 2. ....

@MichaelCurrin
Copy link

I recommend replacing your forward tick with back ticks (on the tilde ~ key)

-´n-body´
+`n-body`

Then it gets formatted neatly in markdown as

n-body

rather than

´n-body´

@whoisashraf
Copy link

You could try the crystal language, it's got a syntax similar to ruby and compiles too using llvm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment