9 ms·
Opal: Ruby to JavaScript Compiler
- seanewest 12y agoHow hard is it to use an existing javascript library with Opal?
- shocks 12y agoWhat is a good use case for this? Interesting project otherwise! :)
- randall 12y agoRuby aficionado programmers who think coffeescript is too pythony perhaps? :)
- bigtunacan 12y agoAs DouweM said; there is a case to be made for having the whole stack in a single language. While I use different languages server side, Ruby (either with Rails or Sinatra) is my go to option more often than not these days. I have used CoffeeScript extensively, but this has always been on contracts where the decision was made by someone else. It is important to learn and use real JavaScript (IMHO) rather than all of these transpiled languages. This is the route I take when I have a choice on the client side; I use JavaScript. If I were to use a transpiled language though Opal makes more sense (IMHO) than CoffeeScript if you are working on a project with a Ruby backend. At least then you are creating a uniform stack and hopefully getting some type of productivity boost for your development team instead of always context switching between different languages.
- csbrooks 12y ago>I have used CoffeeScript extensively, but this has always been on contracts where the decision was made by someone else. >It is important to learn and use real JavaScript (IMHO) rather than all of these transpiled languages. This is the route I take when I have a choice on the client side; I use JavaScript. I've been using Rails and Coffeescript. Intuitively, I feel like using Javascript directly would be better somehow, but I prefer the Coffeescript syntax. (I started using it just because Rails nudges you that direction.) What are the benefits of using Javascript directly instead of Coffeescript in a Rails environment?
- path411 12y agoI don't think there would be much benefit except possibly some minor performance gains. But then to even take advantage of these you would likely have to be extremely proficient in native JS. Personally, I don't really see much of a downside to JS transpiled languages. You are already working with a high-level scripting language. The incredible amount of benefits you gain from using something like Coffeescript or Typescript far exceed any negligible downside to them. (You do have to trust that the transpiled language is good however. You don't want to accidentally start using a bad language that fails to transpile or is simply harder to work with than native js. With Coffeescript/Typescript being very popular, I would consider them both "safe".)
- benaiah 12y agoIf you don't know JS really well, I wouldn't recommend Coffeescript. It's hard to tell what will work correctly and what won't unless you're quite familiar with the actual code the Coffeescript is compiling down to. I don't know how true this is for other transpiling languages, but it's definitely true for Coffeescript. I'm a pretty experienced JS dev, so I know exactly what my CS is compiling to and what that's going to do. If I didn't, CS would make me tear my hair out within a week. As it is, it's just shorthand for JS with a bunch of quality of life improvements (?, no var, etc).
- radq 12y agoThis is a good post by wycats that discusses this: https://meta.discourse.org/t/is-it-better-for-discourse-to-use-javascript-or-coffeescript/3153/19 https://meta.discourse.org/t/is-it-better-for-discourse-to-u...
- dragonwriter 12y agoIt seems to me that complaining that you need to use "real JS" instead of a compiled-to-JS language for web apps is like saying you need to use real machine code instead of a compiled-to-machine-code language for an other kind of app.
- bigtunacan 12y agoThat is an apples to oranges comparison. Hence the terminology difference between transpiler/compiler. A transpiler is a very specific subset of a compiler that takes one language that has a "similar" level of abstraction and compiles it to a different language with a "similar" level of abstraction. C++ compiled to machine code is not at all similar to CoffeeScript transpiled to JavaScript. If you are working in CoffeeScript/TypeScript/Opal you are still likely to need to understand JavaScript to best leverage existing JavaScript libs/frameworks and to build on or debug those tools when necessary. A couple of problems arise when you introduce something like CoffeeScript. Now you have added yet an extra layer of knowledge required to the infinite pool of required knowledge Problems 1) Knowledge required Now your team is required to know CoffeeScript(Replace with other transpiled language here) + JavaScript + HTML + CSS + Backend Language of Choice 2) Hiring pool Eventually you will need to hire someone. This presents a problem from both the employer and employee side Employer Side (Pointy Haired Boss) We use CoffeeScript/TypeScript/etc... so we need to post that as a job requirement. Employee Side Really smart potential employee who wants to apply knows JavaScript; sees posting requires CoffeeScript. This employee hits indeed.com and sees there are <1000 coffeescript jobs total, versus >43,000 javascript jobs. Employee decides to stick with JavaScript and doesn't apply. This is a bit of an old interview and I don't know Jeremy Ashkenas personally so I don't know his current stance of CoffeeScript, but I'm going to post it here since it's from the horse's mouth and I believe it illustrates why using JavaScript is really a better choice. "If the question is 'why is CoffeeScript not a DocumentCloud project?' - it's because I can't justify using it for the main DocumentCloud development. Imagine trying to hire someone. 'You'll have to learn to use a new language that we made up...'" - Jeremy Ashkenas http://readwrite.com/2011/01/07/interview-coffeescript-jeremy-ashkenas#awesm=~oGljICP4yb2Hxu http://readwrite.com/2011/01/07/interview-coffeescript-jerem... 3) Future proofing I'm just going to link back to the same wycats link someone else posted, because it's much more elegant than how I'd put it. https://meta.discourse.org/t/is-it-better-for-discourse-to-use-javascript-or-coffeescript/3153/18 https://meta.discourse.org/t/is-it-better-for-discourse-to-u...
- DouweM 12y agoThere's something to be said for writing the client and server app using the same language. Node.js serves a similar use case.
- nbevans 12y agoWhat is the thing to be said?
- evolve2k 12y agoSorry if you were attempting to troll but if not 'there is something to be said about..' is a phrase which translates along the lines of 'there are definitely good things that could be said about..'
- scotth 12y agoHe's asking what those things are.
- dragonwriter 12y agoThe thing to be said is that client and server often share functionality, and if they are in separate languages, code for that shared functionality is necessarily duplicated in two different languages and must be maintained twice.
- lukasm 12y agoSay you have a function that validates a file written in ruby. Now you want to have client side validation in the browser for good UX. The spec for validation may be complicated or you are not sure about the implementation (no docs, person that written it just left). This is internal format with no good parsing library. I'd try it out.
- dragonwriter 12y agoOr you're completely sure about the implementation, but it may change in the future (because requirements evolve) and you don't want to have maintain two different versions.
- deleted 12y ago[deleted]
- lukesan 12y agoWhat about something like rubular.com inside the browser?
- viseztrance 12y agoI never got to using opal, but I was quite intrigued after watching this https://www.youtube.com/watch?v=GH9FAfKG-qY https://www.youtube.com/watch?v=GH9FAfKG-qY
- lloeki 12y agoI have a few developers that can't wrap their head around too much languages without popping one out. The less variability we have, the more robust the final code will be. Theoretically, all developers are ideal learning machines with a robust CS background and a powerful abstracting mind with infinite time to learn and jump around languages at will, with perfect understanding of each language caveats and idiosyncrasies. In practice, one has to build stuff. This kind of things, while not a perfect solution, allows my team to produce better code more reliably.
- griffinheart 12y agoI was entertaining the idea of using this to make a code combat for ruby when it was open sourced.
- rikkus 12y agoGreat, I love Ruby. But what do I do for debugging?
- atmosx 12y agoIf you use any 'something-to-another' abstraction, be it language, ORM, whatever... You pray that it doesn't come to debugging. Might be a great tool for adding a grain of JS salt. But of course if you want to build an entire project based on JS, you better get a book and learn JS...
- adambeynon 12y ago(Opal developer here). When it comes to debugging, I just use the standard chrome dev tools with source maps. Variables and properties on objects all compile using their ruby names, so viewing local vars and ivars in the debugger is easy. I only ever debug the generated javascript when I am debugging a bug with Opals runtime/internals/compiled code.
- aikah 12y agoafaik,it's not really a ruby to javascript compiler(like coffeescript compiles down to js). You cant write xhr = XMLHttpRequest.new and expect it to compile in js.without importing some libs.
- dragonwriter 12y agoIt is really a ruby to JS compiler. Ruby, however, is not just a thin layer over JS the way CoffeeScript is. The thing you are referring to is a sign of CoffeeScript being a thin layer over JS, not CoffeeScript's compiler being a "real compiler".
- seanewest 12y agoInterestingly enough though they are both transpilers (source-to-source compilers).
- aikah 12y agomy point was it doesnt transpile Ruby to Javascript.
- dragonwriter 12y agoIt does, though; it just doesn't expose things that are exposed in the underlying JS environment to Ruby code without jumping through certain hoops. Which makes sense, because unlike CS, which is tied to the underlying JS environment, Ruby isn't, and exposing the underlying JS environment would make it harder to port general-purpose Ruby code as you'd be more likely to run into collisions with the JS environment that you wouldn't see on other Ruby platforms.
- aikah 12y agoMy use case was an online IDE where instead of using javascript to code webapps,users would use Ruby to do the same.But since opal doesnt expose window object,it's pretty useless for me. Maybe you have a solution for that,but I just didnt find one.
- Yoric 12y agoThe name is a bit awkward, given the existence of Opalang, which is another $SomeLanguage to JavaScript compiler.
- Argorak 12y agoGiven that Opal.rb was started in 2010 and Opalang (back then called opages) in 2010 as well, I would file that under "unfortunate". https://github.com/opal/opal/commits/master?page=107 https://github.com/opal/opal/commits/master?page=107 https://github.com/MLstate/opalang/commits/master?page=126 https://github.com/MLstate/opalang/commits/master?page=126
- Yoric 12y agoI don't remember when Opalang was started, but I joined the project in 2008 :) Fwiw, back then the name was Opa. Opages was the name of the CMS written in Opa/Opalang. Funnily, Opa and Ur/Web were two projects started around the same time and sharing very similar ideas, and they also collided linguistically – in German, Opa == grand-dad, while Ur == ancestor. Anyway, have fun with Opal.rb :)
- Argorak 12y agoThanks a lot for clearing that up (also, my post misses a "?" after opapages)!
- vinhboy 12y agoHow do people know that one lang would compile down to another? Is there something about the lang that make this possible? Also, is it possible that something won't translate from ruby --> js and cause a bug?
- peter-fogg 12y agoRuby and JS are both Turing-complete languages (as with just about any other programming language you'll ever use), which means that one can simulate the other. The simulation might be messy, complicated, or slow, but it will still work. In this case, Ruby and JS are close enough that it can be done without too much trouble (see the compiled JS).
- seanewest 12y agoBut does "anything written in language A can be simulated using language B" imply "A can compile down to B"?
- afarrell 12y agoyes. If you can write a body of code X in language B which performs the same operations as any given body of code Y in language A, then all an A->B compiler needs to do is find X given Y.
- seanewest 12y agoOk, but is finding X given Y tractable? To me, it seems like compiling is translation of source (usually higher level source to lower level source), whereas simulation is more like translation of behavior. Edit: and the ability to translate behavior does not seem to imply the ability to translate source
- Solarsail 12y agoCouldn't you translate source given the ability to translate behaviour? If some behaviour in language X can be simulated by a state machine in Y, then you could just emit said state machine as the translation of the behaviour, give its output to the next state machine, etc. And gradually build up the behaviour of a program in X, but using a bunch of generated code in Y instead of just an interpreter. In other terms, if an interpreter for / simulation of X may be expressed in Y, then for each bytecode / AST node in X you could just inline the bytecode handling you would use in Y into the compiled output.
- ankurpatel 12y agoHow would Opal handle meta programming like method_missing and define_method?
- DouweM 12y agoOpal supports `method_missing`: http://opalrb.org/docs/method_missing/ http://opalrb.org/docs/method_missing/ `define_method` as well: https://github.com/opal/opal/blob/f958d6b2468e57acf7f324e10a06b8a8fe475f55/opal/corelib/module.rb#L256 https://github.com/opal/opal/blob/f958d6b2468e57acf7f324e10a...
- ankurpatel 12y agoThis is not pure way of doing meta programming. It looks at the code to figure out what methods are being called in future. Opal.add_stubs(["first", "second", "to_sym"]); But lets say I am dynamically generating method using a string passed from user input or server then this would fail.
- elia 12y agoI had the same fear at first, but actually if you generate dynamically a method name you need to use `#__send__` (and friends) to call it. Of course `#__send__` supports method_missing: https://github.com/opal/opal/blob/0-6-stable/opal/corelib/basic_object.rb#L13-L31 https://github.com/opal/opal/blob/0-6-stable/opal/corelib/ba...
- sheerun 12y agoSo compile a bad language to worse :) (Ruby developer here) I think it makes sense to transcompile type-checked languages to JS, though. Elm is pretty neat.
- berdario 12y agoSince the Opal developers are reading: I'm curious, do you plan to support Encodings and proper Ruby strings, or it isn't worth the effort, and you'll keep using plain javascript strings? (I tried to look for this detail on the website but came back empty-handed)
- munificent 12y agoI'm going to use this as a little example of why compiling to JS is hard. I work on the Dart team, and people often ask what the big deal about JS compilation is. Opal's compiler is a good example of why it can be hard. I want to stress, though, that I'm not singling Opal out here. I think Opal is a really cool project, and I hope it works well for lots of people. It's just a good example language since it's on HN right now. Let's compile this Ruby code to JS with Opal: a = 0 10000000.times do a = a + 1 end puts a Opal gives us: /* Generated by Opal 0.6.2 */ (function($opal) { var $a, $b, TMP_1, self = $opal.top, $scope = $opal, nil = $opal.nil, $breaker = $opal.breaker, $slice = $opal.slice, a = nil; $opal.add_stubs(['$times', '$+', '$puts']); a = 0; ($a = ($b = (10000000)).$times, $a._p = (TMP_1 = function(){var self = TMP_1._s || this; return a = a['$+'](1)}, TMP_1._s = self, TMP_1), $a).call($b); return self.$puts(a); })(Opal); We'll compare it to some vanilla JS: var a = 0; for (var i = 0; i < 10000000; i++) { a = a + 1; } I don't care at all that the generated code is a little funny looking. That's fine. Opal's code is actually pretty readable to me. What is a problem for some (many?) users is the performance. You'll note that Opal did not compile "a + 1" to "a + 1". Instead it generated "a['$+'](1)". That's because Ruby's arithmetic semantics are different from JavaScript's. To implement those semantics correctly, it needs to use a method call instead of using the built-in arithmetic. We can profile the two using this fiddle: http://jsfiddle.net/3UtNf/1/ http://jsfiddle.net/3UtNf/1/ On my laptop, the Opal code is 264 times slower than the raw JS code. In other words, it runs at 0.3% of the speed of the JS code. Now imagine sacrificing that much perf on a mobile device. That's enough to make the language unsuitable for many real-world use cases. This isn't intractable, though. You just need to compile math down to real JS arithmetic operators when JS's semantics line up with your language's (which typically means, when you're suring you've got numbers and not some other type with a user-defined operator). Determining where you can do that is the hard part. It requires type analysis. Doing that well in a language that doesn't have a sound static type system requires whole-program analysis. It's extremely complex, monolithic, and leads to very strange output code. This is why, for example, Dart's dart2js compiler is so complex and heavyweight. It does do this kind of analysis. It compiles this Dart program: main() { var a = 0; for (var i = 0; i < 10000000; i++) { a = a + 1; } print(a); } to this JS: function() { var a, i, line; for (a = 0, i = 0; i < 10000000; ++i) ++a; line = "" + a; H.printString(line); } That has the same performance as the JS code. The reason it does this is because it knows "a" is a number. If we change the Dart code to: class Foo { operator +(other) => this; } main() { var a = new Foo(); for (var i = 0; i < 10000000; i++) { a = a + 1; } print(a); } Then generated JS changes completely: function() { var i, line; for (i = 0; i < 10000000; ++i) ; line = H.S(new Q.Foo()); H.printString(line); } Interestingly, here you can see the compiler understood that the "+" operator on Foo always returns the same object and was able to inline the call to it and then hoist it out of the loop completely. This is the kind of stuff you need to do if you want to have a language that compiles to JS and (unlike, say CoffeeScript and TypeScript) has semantics that aren't very very similar to JS.
- moger777 12y agoIf performance is an issue, you can drop down back to JS using %x{} or ``. Good idea to do this for mathematical operations.
- adrianlmm 12y agoI pasted in the Chrome console opal generated js code, but I get that "Opal" is not defined.
- adrianlmm 12y agoNever mind, solved. I see potential on this. Thank you.
- steven_yue 12y agoI'd rather learn js when I need to. Auto generation is waste time in this case