Introducing Helix

Introducing Helix

https://slides.com/karunamurti/helix

What is Helix?

RUBY

RUST

What is Helix?

Native Ruby Extension

Include code that needs to be compiled

The compiled code can be required on ruby script

Native Ruby Extension

Traditionally using
C  or  C++

http://silverhammermba.github.io/emberb/

Native Ruby Extension

  • mysql

  • pg

  • json

  • unicorn

  • bcrypt

  • rmagick

RUST

RUST

2006 - Graydon Hoare side project

2009 - Sponsored by Mozilla

2010 - Publicly announced

2011 - Bootstrapping

2015 05 - 1.0

2017 05 - 1.17 Happy 2nd birthday

RUST

RUST

extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
    println!("Guess the number!");

    let secret_number = rand::thread_rng().gen_range(1, 101);

    loop {
        println!("Please input your guess.");

        let mut guess = String::new();

        io::stdin().read_line(&mut guess)
            .expect("Failed to read line");

        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        println!("You guessed: {}", guess);

        match guess.cmp(&secret_number) {
            Ordering::Less    => println!("Too small!"),
            Ordering::Greater => println!("Too big!"),
            Ordering::Equal   => {
                println!("You win!");
                break;
            }
        }
    }
}

RUST

https://insights.stackoverflow.com/survey/2015

RUST

https://insights.stackoverflow.com/survey/2016

RUST

https://insights.stackoverflow.com/survey/2017

Rust

Why?

Ruby is GREAT

but

GC
vs
manual memory management

GC

  • Programmer time is expensive

  • No need for memory allocation and deallocation

  • Slower

  • Less segfault

  • Memory hog even after GC.start

Manual Memory Management

  • Programmer happiness & ergonomics

  • Faster

  • Less memory usage

IO Bound
sometimes the limit is not
computing power, but IO
disk, db connection, network, etc

CPU Bound

image processing, large data processing, etc

Rust vs Other System Language

Memory Safety

  • No memory leak / corruption / null pointer -> borrow checker

  • Automatic deallocation when out of scope

  • Lifetime

Less Security Problem

MemorySafety

No overflow

Speed

People

  • Yehuda Katz (cargo)

  • Steve Klabnik

Best of both world

  • FFI (mysql, json, nokogiri)

  • Helix

Demo

$ curl https://sh.rustup.rs -sSf | sh

Install Rust

or update

$ rustup update

https://www.rustup.rs/

Demo

New rails application

$ rails new --skip-active-record tryhelix

Demo

Add helix

source 'https://rubygems.org'

# ...

gem 'helix-rails', '~> 0.5.0'

Demo

Generate necessary routes, controller, and views

Rails.application.routes.draw do
  get '/ruby', to: 'static#ruby'
  get '/helix', to: 'static#helix'
end

config/routes.rb

Demo

<h1>Ruby</h1>

app/views/static/ruby.html.erb

<h1>Helix</h1>

app/views/static/helix.html.erb

Demo

class StaticController < ApplicationController
  def ruby
  end

  def helix
  end
end

app/controller/static_controller.rb

Demo

Let's add some benchmarking

app/controllers/concerns/current_benchmark.rb

module CurrentBenchmark
  def print_time_spent
    @time = Benchmark.realtime do
      yield
    end
  end
end

Demo

app/controller/static_controller.rb

include CurrentBenchmark

def ruby
  print_time_spent do
  end
end

def helix
  print_time_spent do
  end
end

Demo

app/controller/static_controller.rb

require 'csv'
...

private

def path
  Rails.root.join('tmp', 'some.csv').to_s
end

Demo

app/controller/static_controller.rb

def ruby
  @sum = 0

  print_time_spent do
    CSV.foreach(path, headers: true) do |row|
      @sum += row['id'].to_i
    end
  end
 end

https://dalibornasevic.com/posts/68-processing-large-csv-files-with-ruby

Demo

app/views/static/ruby.html.erb

<h1>Ruby</h1>
<p>
  Total: <pre><%= @sum %></pre>
  Time: <%= @time * 1000 %> ms
</p>

Demo

Generate CsvReader crate

rails generate helix:crate csv_reader

Demo

It will generate some file in crates/csv_reader

#[macro_use]
extern crate helix;

ruby! {
    class CsvReader {
        def hello() {
            println!("Hello from csv_reader!");
        }
    }
}

crates/csv_reader/src/lib.rs

Demo

Let's try it

$ cd crates/csv_reader/
$ rake irb
...
>> CsvReader.hello
Hello from csv_reader!
=> nil
>> exit

Demo

Let's implement. First things first, test

# encoding: utf-8

Gem::Specification.new do |s|
  ...
  s.add_development_dependency 'rspec', '~> 3.6'
end

crates/csv_reader/csv_reader.gemspec

Demo

crates/csv_reader/spec/csv_reader_spec.rb

require 'csv_reader'

describe 'CsvReader' do
  it 'returns integer' do
    filename = '/home/karuna/helix/tryhelix/tryhelix/tmp/some.csv'
    expect(CsvReader.count_id(filename).class).to eq(Integer)
  end
end

Demo

test

rspec

Demo

implement crates/csv_reader/src/lib.rs

class CsvReader {
    def count_id(filename: String) -> i64 {
        0
    }
}

Demo

test

rspec

Demo

test

rake build
rspec

Demo

add dependencies. cargo.io
crates/csv_reader/Cargo.toml

[dependencies]
...
csv = "0.15.0"

Demo

real implementation

extern crate csv;
...
def count_id(filename: String) -> i64 {
    let mut total : i64 = 0;
    let mut rdr = csv::Reader::from_file(filename)
                               .unwrap()
                               .has_headers(true);
    for row in rdr.records() {
        let record = row.unwrap();
        let new_number : i64 = record[0].trim()
                                        .parse()
                                        .unwrap();
        total += new_number;
    }
    total
}

crates/csv_reader/src/lib.rs

Demo

app/controllers/static_controller.rb

def helix
  print_time_spent do
    @sum = CsvReader.count_id(path)
  end
end

Demo

app/views/helix.html.erb

<h1>Helix</h1>
<p>
  Total: <pre><%= @sum %></pre>
  Time: <%= @time * 1000 %> ms
</p>

Personal Thought

  • Neatly designed language

    • Evolution through RFC

    • Package manager (cargo)

    • Test

    • Documentation (markdown and test)

    • Editor support (rustfmt, racer, rustsym, rust language server)

  • Combination between compsci + real world

  • Harder, have to fight compiler

Personal Thought

pub fn add_two(a: i32) -> i32 {
    a + 2
}

#[test]
fn it_works() {
    assert_eq!(4, add_two(2));
}

Personal Thought

//! The `adder` crate provides functions that add numbers to other numbers.
//!
//! # Examples
//!
//! ```
//! assert_eq!(4, adder::add_two(2));
//! ```

/// This function adds two to its argument.
///
/// # Examples
///
/// ```
/// use adder::add_two;
///
/// assert_eq!(4, add_two(2));
/// ```
pub fn add_two(a: i32) -> i32 {
    a + 2
}

Resource Links

  • https://www.rust-lang.org/

  • http://rust-lang.github.io/book/first-edition/index.html

  • http://rust-lang.github.io/book/second-edition/index.html

  • http://rustbyexample.com/

  • https://usehelix.com/

  • http://blog.skylight.io/introducing-helix/

About Me

https://www.linkedin.com/in/karunamurti/

https://github.com/karuna

8+ years software engineering
15+ years experience cloud, linux, sysadmin, netadmin, and devops
7+ years management experience Chief Engineer, CEO

100+ developers and 10+ project managers

 

Introducing Helix

By Karuna Murti

Introducing Helix

Introduction to Ruby + Rust, Helix

  • 960
Loading comments...

More from Karuna Murti