My experience converting a project from rust 0.12 to 1.0

So rust 1.0 is here (well, the alpha version is here)!

Let’s convert my RustyEmitter project from version 0.12.0 to 1.0.0 alpha!

I’ll clone the project again

git clone git@github.com:kentaromiura/RustyEmitter.git

cd RustyEmitter

you can now reset to this commit if you want to try out step by step:

git reset 353da85cf3b9e11d00b41ae4d53b7983a5500e8f

Try building it:

cargo build


…/RustyEmitter/src/lib.rs:4:38: 4:39 error: obsolete syntax: `|uint| -> bool` closure type syntax

…/RustyEmitter/src/lib.rs:4 pub type EventCallback<‘callback, T> = |& mut EventData<T>|:’callback;

                                                                                               ^

note: use unboxed closures instead, no type annotation needed


Ok, so they change some syntax…

After a fast google search I think it’s related to this

http://smallcultfollowing.com/babysteps/blog/2014/11/26/purging-proc/

Seems also the lifecycle syntax changed a bit.

Anyway. Let’s try to fix this then!

git checkout -b upgrade-to-rust-1_0_0

Let’s change

pub type EventCallback<‘callback, T> = |& mut EventData<T>|:’callback;

To

pub type EventCallback<‘callback, T> = FnMut(& mut EventData<T>) + ‘callback;

rerun cargo build and


lib.rs:12:1: 14:2 error: the trait `core::marker::Sized` is not implemented for the type `for<‘r> core::ops::FnMut(&’r mut std::collections::hash::map::HashMap<collections::string::String, T>) + ‘callback


Ok, so it appear that we cannot use Vec<EventCallback<‘callback, T>> anymore as EventCallback doesn’t implement Sized now, that’s because FnMut is a trait, so let’s change that so it refer to a trait object and not just a trait, to do that we’ll change that to:

Vec<&’callback mut EventCallback<‘callback, T>>

After running cargo build again we got 7 error showing.

oh well.

Let’s look at the first one:


error: the trait `core::marker::Sized` is not implemented for the type `for<‘r> core::ops::FnMut(&’r mut std::collections::hash::map::HashMap<collections::string::String, T>) + ‘callback`

…/RustyEmitter/src/lib.rs:25   fn on(&mut self, event_name: String, callback: EventCallback<‘callback, T>) {


Ok, so we’ll have to update the on signature and implementation to reflect the previous change:

fn on(&mut self, event_name: String, callback: &’callback mut EventCallback<‘callback, T>);

Trying another cargo run, we’re down to only 3 errors w00t!

Again, let’s look at the first one:


error: type `core::option::Option<&mut collections::vec::Vec<&’callback mut for<‘r> core::ops::FnMut(&’r mut std::collections::hash::map::HashMap<collections::string::String, T>) + ‘callback>>` does not implement any method in scope named `push`

…/RustyEmitter/src/lib.rs:26       self.events.get_mut(&event_name).push(callback);


So Option do not implement push, seems reasonable, this means that rust now return an Option<T>, we’ll have to change that line to use pattern matching, basically doing:

match self.events.get_mut(&event_name) {

    Some(callbacks) => callbacks.push(callback),

    None => (),

}

It’s fine to do nothing here, as we already check if the key exists, we can refactor later to remove the current has key check and use the None branch instead, but for now just to keep things easy, let’s focus on make this thing build.

next error:


type `std::collections::hash::map::HashMap<collections::string::String, collections::vec::Vec<&’callback mut for<‘r> core::ops::FnMut(&’r mut std::collections::hash::map::HashMap<collections::string::String, T>) + ‘callback>>` does not implement any method in scope named `find_mut`

…/RustyEmitter/src/lib.rs:40     match self.events.find_mut(&event_name) {


Ok, so find_mut doesn’t exist anymore, it makes sense as it’s now the same as get_mut, let’s rewrite it to be

match self.events.get_mut(&event_name) {

\O/ woot! We got it compiling.

Ok, now just check if the tests works:

cargo test

Oh! WAT! Wait, turns out that the fail! Macro doesn’t exist anymore, now it’s has been renamed in panic! -_-.

Ok, let’s find&replace

Still a lot of errors (19), but let’s go from the first down, maybe they’re all related:


error: type `&mut std::collections::hash::map::HashMap<collections::string::String, collections::string::String>` does not implement any method in scope named `find`

…/RustyEmitter/tests/emitter.rs:15         match event.find(&test) {


Ok, some as for find_mut, now it’s get.

Rerun the tests, 17 errors, next one


error: can’t infer the “kind” of the closure, explicitly annotate it. e.g. `|&:| {}`

…/RustyEmitter/tests/emitter.rs:13     emitter.on(test.clone(), |event:& mut HashMap<String, String>|{


Ok, so rust cannot infer that the closure is of a FnMut type, in order to do that we need to help rust infer the type, let’s just add & mut in front of it for now, same on line 38, 76 and 97, next:


type `&mut std::collections::hash::map::HashMap<collections::string::String, collections::string::String>` does not implement any method in scope named `find`

…/RustyEmitter/tests/emitter.rs:40         match event.find(&test) {


Just like before, change find that to get, let’s replace all event.find( to event.get( as there are at least 2 other instances of it.

Ok, last error (I hope!)


the trait `core::fmt::String` is not implemented for the type `std::collections::hash::map::HashMap<collections::string::String, collections::string::String>`

…/RustyEmitter/tests/emitter.rs:77         panic!(“the emitter must never be called instead has been called with this parameters {}”, event);


So the HashMap can’t deserialise into a String, makes sense, let’s change the error so it only returns the size of the hash map (it should never happen anyway):

panic!(“the emitter must never be called instead has been called with {} parameters”, event.capacity());

Save, rerun cargo test and… 5 new errors! -.-;;;


borrowed value does not live long enough

/Users/kentaromiura/experiments/stepbystep/RustyEmitter/tests/emitter.rs:13     emitter.on(test.clone(), & mut |event:& mut HashMap<String, String>|{


So, this error means that the temporary variable where the callback is stored expires just after the emitter.on instruction, so in order to use it we have to store it in a variable so its lifetime will be extended (the rust compiler is so kind to suggest us the solution).

So the first things one tries is to do:

let callback = & mut |event:& mut HashMap<String, String>| {

        match event.get(&test) {

          Some(thing) => {

            if *thing != data_inside {

              panic!(“the data inside the event is not what is expected, expected {}, get {}”, data_inside, *thing);

            }

          },

          None => {

            panic!(“the data expected wasn’t found”)

          },

        }

    };

    emitter.on(test.clone(), callback);

Unfortunately this don’t work, as cargo test will show:


can’t infer the “kind” of the closure, explicitly annotate it. e.g. `|&:| {}`

…/RustyEmitter/tests/emitter.rs:12     let callback = & mut |event:& mut HashMap<String, String>| {


The solution is to change the closure to explicit say that’s a FnMut one in this way:

let callback = & mut |&mut:event:& mut HashMap<String, String>| {

So just adding &mut: after the first |(pipe)

Ok, after changing everything the tests pass again, there are a number of warning,

Mostly telling me to use “”.to_string instead of String::from_str and something about some slice syntax I have no idea what’s about, but I think it’s reasonable to call it a day 🙂

Hoppa Goto Style!

In 1996 I was 12, that very year I learnt my first language ever: gwbasic

Nobody taught me it, instead at the end on my school book I found some mention of it and I start studying it by myself.

I figure out how it worked and learnt all the command described in the book:

REM (for comments)

IF THEN ELSE

CLS (clear screen)

PRINT

INPUT

GOTO

Cool, all those new stuff, I wanted to try to make a program and decided to write down (on paper, no computer available back then) a program to solve all the trigonometrical problem I had, basically choosing the number of angles and then deciding which value I had and compute the rests.

I end up writing pages just for triangles, anyway I pretty much forgot about it once finished because I didn’t had a computer to try it out.

One year later I got my first pc: an used IBM 286 (which btw I later discovered it had a basic interpreter in the rom)

Anyway one day while cleaning my room I found out my old source list and I end up trying my program, it took hours to just copy it onto the my first elaborator because of my awful writing speed at the time, but once done I try running it and it worked perfectly.

I still remember parts of that source, done basically all with print, input and goto (and pen and paper).

Imagine my surprise some years later when I discovered about loops and how much less typing I could have done. oh well.

Anyway this post is not about recall those days but to introduce you to a brand new old style of programming, the goto one!

btw 1996 was also the year JavaScript first appeared (yep I know it was 95, but it was LiveScript back then).

In ECMAScript 262 3rd Edition (the current most implemented and supported version of JavaScript) Goto is defined as a future reserved word and should not be used for this reason, as far as I know goto has never been implemented in any javascript implementation, but worry not!

Even if goto has not been implemented labels have!

Thanks to labels we have a good but slightly different approximation of goto,

The biggest difference is that we have to use two different keywords in we want to jump forward or backward.

So here’s the trick, to jump backward we can place a label and use the continue keyword to jump to that label,

continue need to be inside a loop though, so we’ll have to place a for(;;) or a while(true) around the code we have to jump back to.

So the classic hello world in basic is

10 print(“hello, World!”)

20 goto 10

Following what I told you earlier we can translate it in JavaScript like so:


Ten: for(;;){
  console.log(“hello, World!”)
  continue Ten
}

Obviously in this case both continue or continue Ten will do the same thing

If you want to test this code try this code, remember that it’s inside an infinite loop, so you have to break out that loop like I’ve done here: http://jsfiddle.net/kentaromiura/CZ2fg/

Ok, continue will work ok as long as it’s inside a loop and as long we jump to some previous point in the code, but what if we want to jump forwards?

Let’s look at some classical basic code like this:

10 I = 5

20 if I = 0 goto 60

30 print (“hi”)

40 I–

50 goto 20

60 print (“wow”)

The trick to jump to line 60 is to using the break keyword!


var i=5
Twenty: for(;;){
  if(i==0) break Twenty
  console.log(‘hi’)
  i--
  continue Twenty
}
console.log(“wow”)

http://jsfiddle.net/kentaromiura/52eAk/

Or better:


Sixty:{
  var i=5
  Twenty: for(;;){
    if(i==0) break Sixty
    console.log(‘hi’)
    i--
    continue Twenty
  }
}
console.log(“wow”)

http://jsfiddle.net/kentaromiura/CEM4E/

As you can see break will enable us to do a forward jump and the cool thing is that break don’t even needs to be inside a loop as continue, so instead so we can write it like in our examples and assigning the label to a simple block statement.

So while goto is not directly available in JavaScript the truth is that is has always been available but nobody told you that because they fear the power that can arise from this.

Tagged , , , ,

FAQ: How to do 1 + 1 in JavaScript

The speed and size optimized way

2; //precomputed using abacus technology


As a reusable function pattern

function onePlusOne(){
    return 2 //still very fast
} 

onePlusOne(); //you can do something with this value now, like alert it or better document.write it.


As a configurable function pattern

function plus(a, b){
   return +a + b // no more optimized for speed, but at least you can pass different parameters now
}

plus(1, 1) // this works with any other parameter now like plus(1, 2) but who needs 2 anyways?


The object oriented, prototype way

function Addendum(a){
   this.value = +a
}
Addendum.prototype.add = function(b){
   this.value += b
}
Addendum.prototype.toString = function(){
   return '' + this.value
}
Addendum.prototype.valueOf = function(){
   return +this.value;
}

var addendum = new Addendum(1)
addendum.add(1)
+addendum // basically a standard object oriented way for adding two numbers.


The object oriented, prototype chainable pattern way

function Addendum(a){
   this.value = +a;
}
Addendum.prototype.add = function(b){
   this.value += b;
   return this;
}
Addendum.prototype.toString = function(){
   return '' + this.value;
}
Addendum.prototype.valueOf = function(){
   return +this.value;
}

;+ new Addendum(1).add(1) // you can now add(1).add(1).add(1) until you get bored of it


The MooTools way(TM)

var Addendum = new Class({
   initialize: function(a){
      this.value=+a
   },
   add: function(b){
      this.value+=b
      return this
   }
})

new Addendum(1).add(1).value // or one could implement valueOf if he wants


New MooTools prime way

var Addendum = prime({
   constructor: function(a){
       this.value = +a
   },
   add: function(b){
      this.value += b
      return this
   }
})

new Addendum(1).add(1).value //pretty much identical ...


(One of) the functional way

function add (a) {
   return function (b){
      return +a+b
   }
}

add(1)(1) // this looks like a couple of asses...


Same but working both with full parameters or using a partial invocation / currying way

function add(a, b){
   if(arguments.length == 1){
      return add.bind(null, a);
   }else{
      return a + b
   }
}

add(1, 1) === add(1)(1) // guess what? it's true


Using Monads

// Monad.js MIT License, Cristian Carlesso @kentaromiura mykenta.blogspot.com
function Monad(value){
   if (value instanceof Monad) return value
   this.value = function(){return value}
}

Monad.prototype.bind = function(f){
   var value = this.value()
   if (f === Monad) return this
   if (typeof f === 'function') return new Monad(f(value))
   return this
}

var base = 1;
var transformation = function add1(x){ return +x+1 }

new Monad(base).bind(transformation).value()


By subtracting a negative value

1 - -1 // you can apply the same patterns above if you really want


Same but using auto casting (thanks @Golmote)

!0 - -!0 // this is particolarly useful if your keyboard has the 0 broken
 


@WebReflection 1337 version

var one = 1
one -=- one 


Same but a bit obfuscated

var _ = _ == _
_ -=- _


The inception mode (interpreter inside interpreter)

eval('1+1') //Eviluation!


The ’90 version of above

var One = 1, Plus = '+'
eval([One, Plus, One].join(''))


Using Array unary Math

var a = 1, b = 1

function toUnary(number){
   return Array.apply(null, Array(number)) 
}

function unaryCount(a){
   return arguments
}

with(unaryCount.apply(null, toUnary(a).concat(toUnary(b)))) length


The is it JavaScript or Brainfuck mode (again @Golmote suggestion)

++[[]][+[]]+[++[[]][+[]]][+[]]


Array you’re definitelly too big (thanks @astolwijk)

var a, b = a = 1
[a, b].reduce(function(){ return arguments[0] + arguments[1] }, 0)