top | item 10091454

Imba – A new programming language for the web

319 points| judofyr | 10 years ago |imba.io | reply

171 comments

order
[+] shadowmint|10 years ago|reply
This isn't a competitor to react; its a competitor to ES6/typescript/coffeescript.

React is a template library, not a language.

JSX is a way to write templates, but that's not react, and its not what react does. It's just a shortcut to writing XML.

You could say this is a competitor to JSX, perhaps; but anything more is hyperbole.

People aren't using react and angular because they have a nice syntax, that's just nice, they use them because you can build applications with them.

How do you build ui components using imba? Use react? :P

[+] lhorie|10 years ago|reply
Mithril author here.

It does appear to have a React-like engine here: https://github.com/somebee/imba/blob/master/src/imba/dom.sta..., but from a quick glance, I can't tell if the quality of the engine is any good (e.g. whether it supports lifecycle methods, efficient sorts, jQuery plugins, etc) because there are no docs and I don't really have time to read the whole codebase right now. Same goes for the speed claim: can't tell if it's actual speed or "cheating" by batching multiple redraws on rAF while not batching them in the React demo. I'm guessing the latter.

Also, I'm not sure I agree with claim of readable output js: http://somebee.github.io/todomvc-render-benchmark/todomvc/im... (look at tag.prototype.render). It's not exactly clean, although it's not terrible either.

With that being said, the language does look like it has some improvements over Coffeescript. The lack of docs is a showstopper for me, however.

[+] judofyr|10 years ago|reply
Imba includes syntax for tags (scroll down to "Tags"), virtual DOM diffing, event handling (with touch support). Yes, React is not a language in itself, but there's quite big overlap in what Imba does and what React+JSX does.

You build UI components like this:

    tag event < div
      def render
        <self>
          <h1> event.title
          <p> "Happening on {event.dateString}"
[+] coldtea|10 years ago|reply
>This isn't a competitor to react; its a competitor to ES6/typescript/coffeescript.

Perhaps you haven't looked at the examples.

>React is a template library, not a language.

Irrelevant -- and it's not such a clear cut distinction as you make it anyway.

A new language can have built in first class support for react like templating -- and this does.

>People aren't using react and angular because they have a nice syntax, that's just nice, they use them because you can build applications with them.

Yeah, so the idea behind imba is that if you could do the same things WITH a nice syntax and first class support it would be better.

Seriously do people read TFA?

[+] kbenson|10 years ago|reply
My first thought as well, even though I know little except the marketing about React. It's like if someone said "Foo: a new competitor to Rails", or "Bar: a new competitor to Vim".

That's not to say I wouldn't be interested in reading about a language that could somehow compete with Vim, if that was an accurate statement.

[+] jlebrech|10 years ago|reply
I guess the title should be JS/React
[+] curveship|10 years ago|reply
I just spent an hour looking at the Imba benchmark. Yep, it's cheating. Which is a shame, because I really like the framework as a whole.

The vast majority of the speedup comes from a single sneaky line of code. The majority of their "Everything" benchmark's time is spent in the reorder step. They've implemented this as "remove a random todo, render, push the removed todo back onto the end, render." The Imba implementation, and it alone, caches the rendered todo view, so that they can re-use it once the todo is reinserted.

This single optimization is responsible for the vast bulk of their claimed speed. Removing it puts Imba only 2x faster than React, not 60x.

If you want to try it yourself, look at line 55 of app.js. Change:

    res.push((this['_' + todo.id] = this['_' + todo.id] || t$('todo')).setObject(todo).end());
... to:

    res.push(t$('todo').setObject(todo).end());
Furthermore, this isn't a caching strategy you'd want to use in a real app. It holds onto all DOM nodes ever created, thereby leaking quite a lot of memory.

Again, I think Imba is cool, and fast, just not otherworldly fast. I hope this was just an "oops!" and not an intentional misrepresentation.

[+] sindreaa|10 years ago|reply
Hi there.

This is utterly wrong, and if you had cared to read about what the benchmark is trying to achieve, you would understand (https://github.com/somebee/todomvc-render-benchmark).

You cannot simply remove caching and reusing nodes from the benchmark (which you do with that change). This is the way Imba does diffing, and it would be akin to removing the React virtual dom!

As we mention in the readme: "Even though it looks incredibly boring, the "Unchanged Render" is possibly the most interesting benchmark. All of these frameworks are plenty fast if they only render whenever something has changed. But if the frameworks are fast enough to render the whole app in 0.01ms, you could skip thinking about all sorts of tracking to keep the view in sync."

In a real world app you do not create 1000000 todos. The actual data rarely change that much. As for purging the cache, see comment: https://news.ycombinator.com/item?id=10092454. Quote:

One thing to be aware of is that Imba doesn't automatically remove the cache for you, because we've found that it's tricky to determine when you actually want to purge it. For instance: if mouseOver <something> else <something-else> Just because `mouseOver` becomes true for one frame doesn't mean you want the `<something-else>`-tag to be purged from the cached and removed. Keeping it around is nice for performance and convenience (e.g. state, jQuery plugins). In practice it turns out you want to purge whole pages/sections at the same time, which is way friendlier for the garbage collector as well.

If you _really_ want to not cache things this way, you can change the line to:

    res.push((this['_' + i] = this['_' + i] || t$('todo')).se ...
Which would only ever cache as many dom nodes as there are tasks, but change which nodes are used for which tasks.
[+] sindreaa|10 years ago|reply
I now ran the benchmarks with the this['_' + i] change (which disables per-task caching, but does not really remove any/all caching alltogether. Imba is still 35x faster than react on the 'everything' benchmark (and even faster on the others). I still would write my apps exactly like they are in the original benchmark, but do you agree that the ['_' + i] change removes what you call 'sneaky code'?

UPDATE: Since the performance was just as good with this dumber type of caching I have changed the actual benchmark to work this way. Would you still consider that caching sneaky? If so, I'm not sure what to say. Yes, Imba caches dom nodes for reuse. That is the whole philosophy behind its 'virtual dom'. Now it does not 'leak memory' anymore either, even though this 'leak' is a feature (ref comment about manual pruning) and not a bug.

[+] judofyr|10 years ago|reply
Disclaimer: I've been following the development of Imba while it's been a private project (for six years now). Lately I've been helping out fixing bugs and improving smaller parts of the language.

Having tags as a proper part of the language is very nice. This just works in Imba:

    <ul>
      for event in @events
        <li>
          if event:type == "like"
            <like event=event>
          elif event:type == "comment"
            <comment event=event>
In React I'd have to use `map` and refactor parts into variables. I've been struggling to use React on teams with designers because small design changes can cause rather huge changes in how the code is structured.

Other than that you can think about it as indentation based JavaScript with implicit method calling (`foo.bar = 123` calls the setter `setBar`) and saner handling of `this`.

[+] dugmartin|10 years ago|reply
You can do that right now with CoffeeScript+React and it looks almost identical:

    {ul, li} = React.DOM
    # require in like and comment components here...

    ul {},
      for event in @events
        li {},
          if event.type is "like"
            like {event: event}
          else if event.type is "comment"
            comment {event: event}
[+] RobertKerans|10 years ago|reply
Can't really comment re the language (the tags as part of the language is very nice, I agree), but it's been in development for 6 years and there are no docs? If it were just a Coffeescript fork & just basically a matter of syntax, then maybe fair enough (but LiveScript & CS both have relatively extensive docs), but this project has much grander claims (ie that it's also a high-level framework competitor) + a grand total of a single page of basic info + no particularly useful source code comments. Sorry to dis a project you're connected to, it just doesn't look good in that respect
[+] state|10 years ago|reply
Can you comment on why the project was kept private? Don't mean that as an implicit criticism: I'm just curious.
[+] keithy|10 years ago|reply
I would really like to see React do something like this as a shortcut to having to do map. It would be SO helpful.
[+] ufo|10 years ago|reply
The React API would be much nicer if it could use Javascript generators.
[+] TeeWEE|10 years ago|reply
The author of imba has some problems understanding languages vs frameworks/libraries.

I quote:

  "Imba is a new programming language for the web that compiles to performant and readable JavaScript."
Ok, so i understand Imba is a language spec with an implementation that compiles to javascript.

  "It has language level support for defining, extending, subclassing, instantiating and rendering dom nodes."
Ok so there is special syntax to create DOM elements. Nothing new here. Its just syntax over javascript. What can be done with imba, can be done with vanilla javascript.

  "it is more than 20 times faster than React"
Wait, what? React is a javascript library, not a programming language. Written in javascript.... How can Imba be faster? Does Imba also include a dom-diffing algorithm.. If so, why would you built that into the language... Woudnt it be better to write a library in imba-lang that can do dom diffing? I'm lost here.
[+] nostrademons|10 years ago|reply
There's no rule that says the language/library/framework divide has to lie where contemporary scripting languages put it. In PHP and ColdFusion, HTML is part of the language; in Ruby or Python it's usually relegated to a templating library; in Javascript the DOM is usually a library and it's bad practice to build up HTML strings (in 2015, at least; in 2008 it was good practice to build up HTML strings, because it was orders of magnitude faster than using the DOM). In Matlab or R, statistical and linear-algebra functions are part of the language, while in Python they're a library. In C++, strings, hashtables, and arrays are part of the standard library (or not even that, in early versions), while in Python & Ruby, they're part of the language. In Lisp the language parser is part of the language; in Rust, C++ (under Clang), Python, and Go it's part of the standard library; in many other languages it's not available at all.

There are certain best practices that have emerged for general purpose languages. Imba is not a general purpose language; it's explicitly meant for web programming, and makes sense that it would build common web programming functionality into the language itself.

[+] judofyr|10 years ago|reply
> Does Imba also include a dom-diffing algorithm

Yes.

> Woudnt it be better to write a library in imba-lang that can do dom diffing?

It is: https://github.com/somebee/imba/blob/master/src/imba/dom.sta.... It's a required runtime library if you want to use the tag syntax.

The difference between "language" and "core library" is always a bit mushy. For instance, the JavaScript doesn't only specify the semantics of operations, but also the main objects (String, Array, etc) and a set of functions (push, pop, indexOf, etc).

In the sense that JavaScript ships with default objects for dealing with Arrays and Strings, Imba ships with default classes for dealing with tags and DOM elements. Yes, we could say that tags should just be sugar syntax over regular function calls (which it actually is) and move the DOM diffing out of "Imba". But really, the main point about Imba is the tag functionality and we believe we only need one good implementation.

[+] coldtea|10 years ago|reply
>Wait, what? React is a javascript library, not a programming language. Written in javascript.... How can Imba be faster?

The same way an advanced primitive in a language can be faster than another language + framework code to do the same thing.

What exactly is startling? It's not like languages/libraries and frameworks have some hard defined boundaries. What's a library for one language can be built-in primitives for another (e.g. consider using vectors and hashmaps in C vs Python, or consider something even more powerful like APL or Rebol).

>Does Imba also include a dom-diffing algorithm.. If so, why would you built that into the language... Woudnt it be better to write a library in imba-lang that can do dom diffing?

No, it's not always better to have "a library" vs first class support. Not to mention that some things are impossible to do with regular user code in a language vs first class code (e.g. consider how Go's make() is "blessed" to work as a generic function).

Especially here, where the whole purpose of the language is to be a DSL for web programming and to incorporate all these conveniences.

Nothing new either: we have had languages with first class support for specific use cases since at least the 60's.

[+] pc2g4d|10 years ago|reply
I think they were comparing based on the performance of a simple application:

"For a semi-complex application like TodoMVC, it is more than 20 times faster than React with less code, and a much smaller library."

I think the comparison makes sense because Imba seems to imply a lightweight framework. At least, the generated code in the examples on the front page references a `t$` function, which has to come from somewhere.

[+] viach|10 years ago|reply
"if Ruby and React had an indentation based lovechild, what would it look like?"

Let me guess!... CoffeeScript?

[+] judofyr|10 years ago|reply
Imba was actually forked from CoffeeScript three years ago. After the fork there's been a bunch changes, both in terms of adding tags, but also when it comes to the object model and variable scope.

- Implicit calling: `foo.bar` calls `foo.bar()` and `foo.bar = 123` calls `foo.setBar(123)`

- Objects have instance variables that's separate from the methods. Well, technically the instance variable `@bar` is just stored as a property with name `_bar` on the object.

- Variables must be declared with `var` and they correctly shadow previously defined variables.

- `do` provides a syntax sugar for the pattern "function as the last argument"

- Optional arguments work together with block parameters

    def timeout(amount = 0, &cb)
      cb(amount)
Compiles to:

    function timeout(amount,cb)
      if(cb==undefined && typeof amount == 'function') cb = amount,amount = 0;
      return cb(amount);
    };
- `self` is a keyword which is a saner `this`, and instance variables are automatically looked up using `self`:

    def end
      @client.on("end") do
         @server.end
Compiles to:

    function end(){
      var self=this;
      return this._client.on("end",function() {
        return self._server.end();
      });
    };
[+] _hadrian|10 years ago|reply
yeah, just add the jsx to CoffeeScript :D
[+] meowface|10 years ago|reply
I actually think this looks really good, but 3 things:

1. Why differentiate it from CoffeeScript so much? Why not call it DOMCoffeeScript or something? Are there any core language changes from CoffeeScript other than the tag features?

2. I'm not sure how I feel about the mixture of XML tag characters with HAML/Jade-like indentation. My gut instinct is to always look for a closing tag with XML/HTML. Why not use some kind of sigil like % or @ or ! to represent a tag, since clearly the requirement for both a left and right caret is now obviated?

3. Why require the `var` keyword instead of making it the default? That's one of my biggest pet peeves with languages like Javascript and Lua. Local-by-default always makes the most sense.

[+] curveship|10 years ago|reply
I can't speak to #1 and 2, but for #3, one of the criticisms of CoffeeScript has been that defining local variables and modifying variables from an outer scope have the same syntax. I.e., if I see `foo = 1` in a piece of code, I don't know if it's creating a local variable called foo or modifying a variable called foo from a containing scope -- the only way to tell is to scan all the containing scopes for a variable called foo. Even worse, let's say a piece of code had an inner function that declared a variable foo, but I then declare a variable called foo in an outer scope. That inner statement now silently switches from declaration to modification. I suspect this is why they force the use of `var` for declaration -- it disambiguates the two cases
[+] judofyr|10 years ago|reply
1. Because the semantics are quite different. See my other post.

2. It's still nice to separate the attributes from the content:

    <h1 title="hello"> "Foo"
Why use a new syntax when everyone knows HTML/XML?

3. The lack of `var` in CoffeeScript is its worst feature ever IMO! Every time I write `someVariable = …` I'm terrified that I will accidentally overwrite a previous variable. Imba improves on JavaScript here and will correctly shadow multiple `var` in the same function.

[+] Too|10 years ago|reply
#3. Python did the mistake of not having a var keyword. When you have nested closures you don't know if you are assigning a variable in the outer scope or the inner. You have to use hacks like creating an array of length 1 in the outer scope if you want to modify it in the inner scope otherwise you create new variables in the inner scope each time you try to make an assignment.

Now they created a new "nonlocal"-keyword to cope with this but it wasn't added until version 3.0. https://www.python.org/dev/peps/pep-3104/ has a great summary of all this.

[+] aidenn0|10 years ago|reply
Contrariwise, implicit creation of local variables is my biggest pet-peeve with languages like Python, so ymmv.
[+] mangeletti|10 years ago|reply
I have to admit I was really not excited to see this:

    var answer = if number == 42
The language looks shockingly pleasant in a number of ways, but everything being an expression seems odd. Would somebody mind helping me understand the value (semantic, performance, etc.) of such a choice?
[+] untog|10 years ago|reply
CoffeeScript (which this is forked from) has some parts like this that I strongly dislike, such as using the unless keyword after an action. For example:

    doSomeThing() unless person.present
For me that utterly destroys readability - in my mind, when I see a (), that function is being called there and then. The fact that you can invalidate that later in the line confuses me deeply - and it doesn't really provide any benefits above an if statement anyway.

The rest of CoffeeScript is great though, don't get me wrong. (though ES6 JavaScript has taken the best features anyway)

[+] Q6T46nT668w6i3m|10 years ago|reply
Technically, the language has patterns (e.g. identifiers) too.

A major semantic benefit of expression-oriented programming is minimizing state while maximizing composition (e.g. compare and contrast a switch statement to pattern matching).

[+] matthewmacleod|10 years ago|reply
This comes directly from Ruby via Coffeescript.

It's aligned with a general approach of reducing syntax noise, and it can result in some really nice, clean code. It leads to a whole class of syntax possibilities, like implicit returns.

There are probably some performance arguments against this in the case of Coffeescript, especially wrt constructing expensive return values that are immediately discarded. The consistency is nice, however.

[+] nailer|10 years ago|reply
I don't think of react as a language, but rather a virtual DOM + JSX.

This looks like a nice modern syntax which is both an ES6 focused minimal JS (removing unnecessary tokens) with HTML building included.

[+] endymi0n|10 years ago|reply
So this is basically coffeescript. Where's the react part?
[+] nailer|10 years ago|reply
Scroll down to 'Tags'.
[+] javajosh|10 years ago|reply
Okay, so I just took Imba for a little spin. Some thoughts:

I like the way it looks. A lot. Love, love the tags. Really like the simplified object literals. The use of global variables for class state is deeply troubling - they are not scoped at all. The parser is far too forgiving. if you change do |x| xx into something like do x xx it will compile fine, but be wrong. The tooling is quite nice, and I like the defaults - although it's still a little bit of a mystery where the imba.js file comes from in the Hello World browser example (I ended up just copying it from Github). I'd like to see argument comprehensions, and the option to generate code outside of an immediately excuting function (so I can play with instances at the dev console)

I would like to see a "strict" mode for imba that chokes on a do block without pipes, for example. I think that if JavaScript has taught us anything it's that anal compilers might frustrate us at build time, but that frustration is nothing compared to the frustration down the line when things break at runtime.

[+] sindreaa|10 years ago|reply
Thanks for the feedback. What do you mean with global variables for class state? We do consider moving class-bodies inside an actual function (again) - but there is a virtual scope there in the compiler. So

    class A
	var i = 10
    var i = 20
Compiles to

    function A(){ };	
    var i1 = 10;
    var i = 20;
So they are actually scoped even though it does not look like it in the compiled js. I'm looking really forward to improving the sublime plugin to show much more stuff from the compiler and warn about calls to undefined methods etc. There is a lot of analysis from the compiler that can be used to improve the ide-like experience.
[+] rushabh|10 years ago|reply
As someone who has been developing using Javascript for 10 years and has seen many frameworks comes and go (including authoring one), this looks refreshingly good on first impressions. Far better than coffeescript or React. Congrats!

Plus, I love the fact that the syntax looks Pythonic :)

[+] raffomania|10 years ago|reply
Is there more information about how the 'very efficient rendering' part works?
[+] judofyr|10 years ago|reply
There's two parts of the "very efficient rendering":

1. It store the previous rendered tag and does a diff. (Just like React).

2. Every tag is compiled to JavaScript that's easy for the optimiser.

    tag event < div
      def render
        <self>
          <h1 bar="123" baz=bar> "Hello world!"
Compiles to:

    // Setting up the tag-object. Then:
     tag.prototype.render = function() {
       return this
         .setChildren(Imba.static([
           (this.$a = this.$a || t$('h1').setBar("123")).setBaz(bar)
         ], 1))
         .setText("Hello world!")
         .synced()
    }
While React passes an object of props around, Imba will instead call setters. These setters are very easily inlined by modern browsers. Also note that it caches directly on the tag object itself which gives another additional boost. Since it caches the objects themselves it can also compare everything with `===` and/or `indexOf`.

The `Imba.static`-call marks an array as static which is a guarantee that the structure of the array won't change. In this case Imba will not do the full diff-algorithm, but instead compare each item element-by-element.

And yes, once you've achieved the minimal amount of DOM changes needed (like React), the next step for performance is all of these little tweaks. Does it matter? It all depends. Imba is capable of rendering bigger applications than React when you use the "render everything over again in the animation loop".

TLDR: The tags are more integrated into the language. The language is also designed around features that's easy for the optimiser.

[+] rgbrgb|10 years ago|reply
We've been using this coffeescript/jsx project throughout our codebase: https://github.com/jsdf/coffee-react

Similar idea but just ads JSX tags to Coffeescript (cjsx).

Only ergonomics problem is that the syntax highlighting sometimes breaks on single quotes used within the XML tags so you end up having to do something like `<p>{"you're fired"}</p>` so that it doesn't mess up the highlighting in your whole file.

[+] thom_nic|10 years ago|reply
So... I don't understand if you're supposed to use this with react, or instead of react?

If the answer is "instead," is it a language and a view framework?

[+] cpursley|10 years ago|reply
Interesting, great work. As someone who's never been able to get on board with JavaScripts syntax, this looks like a viable alternative to CoffeeScript.

Also, for React applications I've found that LiveScript (a functional compile to JS language) makes for a great JSX alternative as shown here: https://arch-js.github.io/docs/02-basic-tutorial.html

[+] PSeitz|10 years ago|reply
I usually don't like the javascript transpiler languages, but this one seems really decent. The classes are even more powerful than those in ES6
[+] gaigepr|10 years ago|reply
Personally, I am really over the white-space as a delimiter in my programming languages. I used to love python but that is a long lost love.
[+] cheapsteak|10 years ago|reply
What made you change your mind/tastes?
[+] abecedarius|10 years ago|reply
The tag syntax looks like the biggest advantage over ES6. Couldn't ES6 do that though as a template string type? -- like

    dom`<div> ${contents} </div>`
As far as I can tell on a quick google, this remains to be done. (I saw some hits for HTML string templates as opposed to direct DOM construction.)