If you're not into Opal, how can we convince you?

Perhaps there’s something in particular that is preventing you from making the switch - what?

2 Likes

Opal looks pretty good, and I’m sure that it works really well, the thing is, I already have CoffeeScript and Underscore in my pipeline, and as a result, my front-end code already looks pretty much like Ruby. Not exactly, but then again, it’s not like it matters much (to me), because the code on the front-end is very different from the code on the back-end anyway, even if everything was purely in Ruby, it’d still feel like two different world - one concerned with SQL, one concerned with HTML to simplify heavily the main difference.

That being said, assuming I was starting from a blank slate, new project, all choices are back on the table, etc, I’d ask myself:

Do I want to write:

Element.find('#header').on :click do
  puts "The header was clicked!"
end

Or do I want to write:

$("#header").on "click", ->
  console.log "The header was clicked!"

Meh, the latter feels less verbose. But that’s nitpicking.

Do I want to worry all the time about the overhead introduced by Opal? By overhead, I mean:

Turning this:

class User
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def admin?
    @name == 'Admin'
  end
end

Into:

/* Generated by Opal 0.8.0.beta1 */
(function(Opal) {
  Opal.dynamic_require_severity = "error";
  var self = Opal.top, $scope = Opal, nil = Opal.nil, $breaker = Opal.breaker, $slice = Opal.slice, $klass = Opal.klass, user = nil;

  Opal.add_stubs(['$attr_accessor', '$==', '$new', '$puts', '$admin?']);
  (function($base, $super) {
    function $User(){};
    var self = $User = $klass($base, $super, 'User', $User);

    var def = self.$$proto, $scope = self.$$scope;

    def.name = nil;
    self.$attr_accessor("name");

    def.$initialize = function(name) {
      var self = this;

      return self.name = name;
    };

    return (def['$admin?'] = function() {
      var self = this;

      return self.name['$==']("Admin");
    }, nil) && 'admin?';
  })(self, null);
  user = $scope.get('User').$new("Bob");
  self.$puts(user);
  return self.$puts(user['$admin?']());
})(Opal);

vs CoffeeScript:

Turning this:

class User
  constructor: (@name) ->

  isAdmin: ->
    @name == "Admin"

Into this:

var User;

User = (function() {
  function User(name) {
    this.name = name;
  }

  User.prototype.isAdmin = function() {
    return this.name === "Admin";
  };

  return User;

})();

This isn’t magic, this is very simple and I’m confident most JS engines will optimize the heck out of this. It’s gonna be as fast as JS could be (very simple Inline Cache mechanism). I do not believe Opal’s generated code is as clean and straightforward as this. Maybe it’s “clean” from a certain point of view, but to me, it almost looks like PHP (that’s with all the $ ;)) and that’s not a great sign. More seriously, I think it’s fair to assume that good Opal generated code will not be, in most cases, as fast as good CoffeeScript. That’s a serious issue for me because my Javascript is slow enough as it is, if I have to think about how to translate the Javascript optimization into Opal, then I think it’s really backward.

As a related concern, when working with other libraries, there will always be a kind of “context switch” between libraries in vanilla Javascript and librairies in Opal that you are currently debugging in the browser, in their raw, hard to parse (for me) JS form. I do not want to have to learn this whole new thing, especially when one of the main idea of “client side ruby” is to not have to work in two langage. Unless I’m mistaken, Chrome Dev Tools doesn’t understand Opal and will work with the generated JS. Even with source maps, it’s still not very convenient.

It’s the first time I put those things in words so I apologize if it’s a bit messy. I have been following Volt and Opal at a distance, but so far, I don’t really see what problem is being solved, and the issues/concerns it introduces far outweigh whatever the advantages are. This is obviously a very personal opinion.

Cheers!

1 Like

Hi @Enders Enders, thanks for your thoughts on Opal - it’s always good to hear why people have chosen not to use it or give it a go… but you didn’t answer my question - how can we convince you?! Just kidding :smile:

I’ll go through your points here myself, but hopefully someone much more experienced with Opal than me (like @vais and @fkchang2000) will chime in as well.

Firstly you comment on verbosity, and tbh, being the most verbose language was never really a design goal of Ruby (and I guess it isn’t one of the things I personally look for in a language either). I actually dislike how Python and CS are so verbose, opting to use indentation the way they do.

So in the examples you provide:

Element.find('#header').on :click do
  puts "The header was clicked!"
end

and:

$("#header").on "click", ->
  console.log "The header was clicked!"

I actually prefer the Ruby/Opal code because it just makes so much sense to me. Also your code helps demonstrate the mental shift we often talk about - when you read Opal, it’s just Ruby, but when you read and write CS you are shifting your mindset to another language that in many ways is similar but still very different to Ruby (as opposed to HTML & CSS which are just very different - so the shift isn’t so jarring).

On overhead.

I think you make a fair point. But (there’s always one isn’t there!) is it a worthwhile sacrifice? You already made a similar sacrifice when you choose to use Ruby instead of C.

Also, this leads us to an important positive of Opal - that when you write Opal, you are not just writing translated JS (into Ruby) code, but you’re actually able to write as if you were writing Ruby - in other words you can harness and use the power and mechanics of Ruby.

If raw speed is an issue, you could, when/if you ever need to, just use plain old JS through Opal.

With regards to the generated output in relation to debugging, then yeah it is more to work through (though Opal has source maps which make things much easier) however it’s also worth asking whether you’d actually have less bugs because you’re writing in Ruby than (that just makes more sense) than JS? (Not trolling, honest!) This is a point I have seen made by others a fair few times now.

Libraries and context switch

Again you make a fair point… but why not make a thin wrapper? Opal-react is a great example, and there’s even one for making games with Phaser (Opal Phaser).

Problems/solutions

Ok my reply is getting a bit long now (sorry!) so I’ll wrap this up on your final point - which problems are Opal and Volt solving?

For me (with Opal) it’s simply allowing me to use my favourite language (and pretty much everything I like about it) in the browser. It’s also about not having to use a language that I am really not that keen on (JS/CS) (though I accept this is less of an issue for some people).

With Volt, there’s that, and a lot more - the framework is really thoughtfully put together. I often comment that if Rails was being created today, it probably would have opted to go down a similar path. Actually let me just quickly quote part of my next blog post on Volt (which I haven’t published yet):

I hope I’ve not missed any points, and please don’t apologise about your post - it is very well articulated and not at all messy! :slight_smile:

1 Like

On the overhead / performance issue, I like to think of this as an investment vs a losing proposition of speed. While I realize that Opal is relatively young, I also recognize that I’m writing in pure Ruby. To me this means that I know that my investment is safe and that as Opal matures and grows, the optimizations will improve dramatically.

I believe that we all will have our eyes seriously set upon performance once we hit a 1.0 release. That belief in itself brings a high degree of confidence to my efforts vs jumping into something like CoffeeScript or (RIP) Dart that, to me, are not primary languages and have questionable futures at best.

While we’re waiting on the overhead / performance end to meet up with our needs and to obtain the functionality of a very robust and mature game engine, we’re using opal-phaser (Twitter) to build a remarkable new project entirely in Ruby with Volt. The realtime reactivity is fantastic and the isomorphic vertical Ruby is a dream come true.

1 Like

@AstonJ you might also make note that the MVVM approach is more akin to app development that so many are leaning towards today. Further, RubyMotion is on the “todo” list for Volt to support. Won’t it be nice when we can build a Volt app and essentially deploy it via RubyMotion as an app on iOS and Android devices? A vertical Ruby experience that is cohesive and makes writing and debugging more of a pleasure from backend to all front end platforms. That is a remarkable vision compared to our currently accepted paradigms.

1 Like

Yep, I totally agree :smile:

There’s an excellent video of a talk by some of the Github devs recommending MVVm - I need to find the link (I’m gonna link to it in my next blog post about Volt too). It’s what sold me on it.

I’ll try and look for the video later…

Well I think the main part into convincing people into Opal is actually making couple of tutorials of converting native classes/objects/libraries into ruby ones. Documentation lacks on that points and one has to do such things experimentally.

For example it would be nice if there would be tutorial how to wrap libraries into ruby classes. It can be something absolutely micro.

Well it took quite time for me (coding is my hobby, don’t judge me) to experimentally convert

`router.get(':foo', function(req){
      var id = req.params.foo;     
      console.log(id);

  });`

into:

router = Native(`new Grapnel({pushState: true})`)

  router.get '/:foo' do |req|
    req = Native(`#{req}`)
    id = req.params.foo
    puts id
  end

Yeah Opal is divine gift for us. But no one want’s to mess with reinventing stuff and libraries that already exist. So I think that needed.

I pray to computer gods for Opal to be popular, so people start doing things with it.

Hello !
That’s a really interesting post.
I must say I WANT to use Opal. Like, really. I’ve been trying, many time, but without success.
Compiling a file from .rb to .js is one thing. But building a full stack based on Opal is another one.
First of all, I tried to build a React+Opal stack : no luck. Client side rendering was working, but no way I could build it with server side rendering.
Then I tried to build another one long after (3 weeks ago actually).
I was basically using Webpack to build my scripts. my main (Only?) concern was issues with requiring existing libs.
Managing my web-lib with gem is an hassle, and I’d love to use npm instead, but here’s the catch : you can’t properly integrate Opal with JS. And that’s what is stopping me.

Basically I want to write the following :

require 'angular' # from npm_modules/angular installed using npm
....
angular.app(...)

I tried many work arround like writting :

angular = `angular`

Because ` are supposed to allow gateway from rb to js, but no success.

Anyway, to answer your question roughly, when I’ll be able to use my npm libs from ruby in a seamless way, I’ll definitely switch.

1 Like

when I’ll be able to use my npm libs from ruby in a seamless way, I’ll definitely switch

https://rails-assets.org is a site that gives you gems from npm modules. Their system provides an online gem source that simply wraps npm packages into working gems.

There are other tools that do something similar but I don’t remember what they are.

2 Likes

Hey thanks for the tool
It’s an interesting tool though it does the complete opposite than what I expected
Ruby-asset allow you to install assets as Gem packages and include it in your JS
I’d like to install my asset as JS packages (using npm) and use it in Opal.
The main difference is that, even thought my asset would be installed using Gem in ruby-asset (or any similar tools), they would still be unavailable to require in Opal (As far as I know) because they are just Assets, not Ruby modules.
The goal of this tool is (as I understand it) to manage all your dependency in one tool (Bundler) when having a Rails project, instead of having server dependencies in Bundler and assets in another tool like npm or Bower.
Correct me if I’m wrong