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.
> The lack of docs is a showstopper for me, however.
That's a fair criticism. We know that docs are severely lacking. But at one point you'll have to release it. The reason it's been private for all these years is because there's always been just one more thing to fix.
And this is just an open-source project. We just think this is a cool technology and want to share it with the rest of the community.
> Same goes for the speed claim: can't tell if it's actual speed or "cheating" by batching multiple redraws on rAF and while not batching them in the React demo. I'm guessing the latter.
Hah, we talked about this before the release. We actually thought about publishing worse results (or adding some code to slow it down) because we were afraid people wouldn't believe it.
requestAnimationFrame isn't used in this demo. The repaint/redraw is not the thing we are trying to benchmark. We might as well hide the whole app during the benchmark, or even detach it from the document. It is trying to measure the performance of bringing the whole view "in sync". If there is something wrong with the way Mithril is forced to render, please file an issue.
There's probably some more lifecycle methods that could be useful, but the amount of lines written in Imba is in the magnitude of 100k. The current approach has been adequate for that.
The sorting is quite efficient. We find the minimal amount of nodes that needs to be reordered. jQuery plugins should work fine as long as they don't touch the parents too much; Imba is quite good at keeping the DOM-node in the tree.
Hi, just wanted to clarify I'm not trying to badmouth, just pointing some things that weren't clear to me (as someone who would be qualified to evaluate the quality of a React-like framework). Lack of docs aside, it does look like a nice project :)
> requestAnimationFrame isn't used in this demo
Interesting. Gonna look into the project more when I get a chance then.
jQuery plugins, from my own experience, are quite naughty. Modals, tooltips and drag-n-drop things are examples of things naive people might try to throw at the system and wonder why things get wonky.
You are absolutely right, and I agree. When you use static tag trees in Imba (with inline caching) the code is not readable. If you only use it for regular things you would write in js (classes, functions, etc) I still think it is quite readable.
BTW, I really love the simplicity of Mithril. It is a very impressive project.
Yeah, for non-tag stuff, the output does look clean. I mentioned this for tags because I didn't see source maps. Transpiled code needs to either output source maps or it needs to be reasonably traceable-by-hand back to the source of a bug (say, in the case a null ref exception)
I just commented below after looking over their benchmark. In it, the Imba implementation, and it alone, is caching and reusing the rendered todo views (globally, forever -- hello memory leak). Without that, they're only 2x faster than React and Mithril, not 60x.
rAF batching isn't an issue. They perform a render(true) after each change, effectively making all frameworks work synchronously.
Other than that, it is an interesting framework, and I wish them well.
See comment: https://news.ycombinator.com/item?id=10095990. Thanks for taking the time to looking through the benchmark. I think you are misinterpreting things. Yes we do caching, and yes IF your app created a million tasks every second you would need to manually dereference them at some point. But you could change the caching (as mentioned in the comment) to never cache additional tags (instead of disabling all caching - which would be like going into the code of Mithril and React and remove all checks in the virtual dom).
I'm really glad to hear that it is still faster even when removing caching. That, to me, is quite insane. But if you wrote a TodoMVC app in Imba, you would do it _exactly_ like the one that is benchmarked. We have even considered adding asserts to warn users if they use uncached nodes in rendering that happens very frequently.
You are actually right that Imba does not dereference these automatically (see other comment re purging by judofyr: https://news.ycombinator.com/item?id=10092454). We could dereference unused tags once every second or so, but for now we think it is better to have manual control of this. Again, how much is usually happening during a render-cycle? Basically nothing. This benchmark is trying to look at how expensive it is to rerender the whole view. Maybe I should make the "Unchanged render" benchmark the main attraction (as it is the most important) -- but it is quite boring to look at.
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}"
I find the structure of an Imba app rather intriguing; the view+rendering (i.e. tags) almost looks like an upgraded HTML/HAML (possibly akin to EnyoJS).
tag #app
def dirty
persist
render
def add title
if title.trim
TodoList.push(TodoItem.new(title.trim))
dirty
self
And the view+rendering (literally the whole "upgraded-HTML" of the app) is so compact:
def render
var all = TodoList
var active = all.filter do |todo| !todo.completed
var done = all.filter do |todo| todo.completed
var items = {'#/completed': done, '#/active': active}[hash] or all
<self>
<header.header>
<h1> "todos"
<new-todo-input.new-todo type='text' placeholder='What needs to be done?'>
if all:length > 0
<section.main>
<input.toggle-all type='checkbox' :change='toggleAll'>
<ul.todo-list>
for todo in items
<li[todo]@{todo.id} .completed=(todo.completed) .editing=(todo.editing) >
<div.view>
<label :dblclick=['edit',todo]> todo.title
<input.toggle type='checkbox' :change=['toggle',todo] checked=(todo.completed)>
<button.destroy :tap=['drop',todo]>
<edit-todo[todo].edit type='text'>
($$(.todoapp) or $$(body)).append #app
I'd enjoy being able to code a SPA like this, I think - nice work! If something this clean is already possible in some other language/framework/library, I'd love to hear about it (since I haven't been following recent JS developments closely).
edit: @judofyr, the Scroller example app doesn't work for me on Firefox 40.0.2 on Win 8. It works in Chrome.
It looks similar to React's one-way data flow - that render method produces the whole app view, and refers to all the necessary variables. When an event occurs [e.g. the user types text to add and hits enter]:
- the appropriate method is called [e.g. add]
- which mutates the state [e.g. TodoList.push(TodoItem.new(title.trim))]
- and then render is called, which updates the view/DOM
So in a sense it's not really data-binding, IMO - instead, the render method contains the entire view + view logic, and it gets called each time the state is changed.
I can only conclude that you're so focused on aggressively dismissing this person's work, in the typical HN fashion, that you didn't actually read the comment you responded to, or any of their other responses throughout this thread.
You say:
>You ALSO need a library to do the virtaul dom stuff and/or data binding to write an application.
OP says:
>Imba includes syntax for tags (scroll down to "Tags"), virtual DOM diffing, event handling (with touch support).
>Although Imba was started before React it should be noted that it didn't include virtual diffing until React showed that it worked.
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.
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:
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.
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:
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.
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`.
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}
Imba was started before React was available so it wasn't an option back then. As for today, the language integrates tags in a much nicer way than what's possible with CoffeeScript + React. This especially pays off performance-wise.
Although Imba was started before React it should be noted that it didn't include virtual diffing until React showed that it worked.
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
Unfortunately we were too busy building actual applications. In total it probably sums up to a number in the magnitude of 100k LoC.
EDIT: But yes: Docs are lacking, and that is a reason for you to not pick Imba for a project right not. We'd still think it would be worthwhile for you to checkout though. There's some interesting ideas in there.
I will do! I didn't mean to be too down on it, just slightly disgruntled when I tried to locate semi-detailed docs. Looking forward, and given you've been building real stuff in it, maybe worth writing up how you've used it, how how the features have been useful, how projects have been structured, how they fit into workflow etc.?
The benefit of JSX is its syntactical simplicity. Lots of beginners seem to think JSX adds all kinds of language features but in reality most of them are unrelated to JSX and either part of ES6 or experimental features of ES7.
The only new thing JSX brings to the table is the element syntax. And all that does is translate `<a b={c}>{d}</a>` to `React.createElement(a, {b: c}, d)`.
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.
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.
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.
>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.
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.
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.
- 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
There's one historic reason (it wasn't widely available when Imba was started). Another reason is performance: the last time we benchmarked this `defineProperty` was slower than regular function calls. Maybe it's improved now.
Semantically the biggest difference is that you don't need to do anything special for marking a method as a property:
class List
def length
# …
In this case `list.length` just works. The disadvantage of this is that if you want to get the function itself, there's a separate syntax (`list:length`). Other than that, this is mostly about taste/style.
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.
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
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.
<label>
<input:checkbox:checked#myCheckbox>
<span> Some Text
Might be nicer than actually spelling out the attributes and properties, if you're taking an already wrist friendly language and bolting on tags, then taking that a step farther would probably be a nice idea as well.
But for 3... so you never use languages like Ruby or Python? Variable assignment shadowing is always possible in those languages, yet for seasoned developers, it tends not to be a real issue.
#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.
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?
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)
As a Perl programmer, I'm often using contructs like that, and I think they have a place, but you should restrain yourself from using them in places where they can easily be misunderstood.
For example, they work really well in loop control statements:
for my $i (1 .. 100) {
next if $i == 10;
next if skippable($i);
last if is_what_we_want($i);
# Do stuff here
}
Or more complex param validation
sub foo( $arg1, $arg2 ) {
return unless $arg1 > 10;
die "Invalid argument arg2!" unless defined $arg2 and $arg2 =~ /^(?:CAT|DOG|GERBIL)$/;
# Do something
}
That said, I don't like it for assignment of in that manner (at least where the assigned value comes out of the if), because the main justification for allowing it (it's a natural extension of how we think) doesn't follow. A ternary operator is better in that instance, IMHO.
That's not specific to 'unless' – it's the general postcondition style that's is derived from Ruby. Indeed, for single-line if statement bodies in Ruby, it's the recommended style.
It fits the style of Ruby to try and cut down on syntax noise where it's not needed. Contrast:
save! if !record.persisted? && !record.invalid?
save! unless record.persisted? || record.invalid?
Though I do appreciate it's a bit unusual compared with most other languages – CoffeeScript does owe a lot to Ruby's syntax.
The behavior here, if it comes from Ruby, almost definitely has it's legacy in Perl, so you can look to Perl for justifications. The main justification is likely to be that's a natural construct of how we think and communicate, so why not allow us to express ourselves that way?
Another way to look at it is why do you think the conditional should come before like you've shown? Because C or even older languages started with that? If you didn't have prior experience with that form, would you still think it's inherently better, or would the trade-offs between the two forms seem slightly more balanced?
The same applies to while/until loops, which can lead to quite succinct code.
I've been using it for a long time, so I don't find it confusing at all – but I agree it's pretty rare to find, so I'm not surprised to find out some people would rather not see that!
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).
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.
Does Ruby allow the value of the if statement to be used as the RHS of an assignment? That's surprising. In Perl, which I assume they got that from (it's a fairly safe bet, Ruby is heavily Perl influenced), postconditionals are not allowed to be used as a statement, they are statement modifiers. You can do this:
$v = 1 if $v < 1;
return unless defined $param;
die "died!" unless $param > 10;
But you cannot:
$v = if $v;
You also cannot use else on postconditionals (if it's that complex, you need a traditional if statement).
And that's different than in Perl, where they aren't statement modifiers (I slightly misspoke), they really are just rearranged into single statement if blocks. That is, if the postconditional is false, the statement is not executed at all.
my $x = 1;
$x = 10 if $x > 1;
say $x; # 1
Personally I find the assignment of the if/else statement's return value distasteful, as it's both complex to read and mixes a portion of a natural pattern of thinking while later abandoning it, making it unintuitive. At that level, I prefer a ternary operator.
Algol 60 had conditional expressions. Pretty much every functional language and LISP has them. They've also been in use in mathematics for longer than computers have been around.
Hi. We actually do a different kind of diffing - which turns out to be substantially faster than React: http://somebee.github.io/todomvc-render-benchmark/index.html. The language has just been released, it is still very lacking when it comes to documentation. Working on it :)
Imba only uses `===` for diffing. If you want Imba to re-use a DOM node, you must use the same tag object. Imba provides syntax for caching nodes as properties on the current object.
For instance, in order to re-use DOM nodes in a for loop you do this:
for event in @events
<event@{event.id} name=event.name>
The next time you render the view, Imba will find the tag objects that have been reordered (using `===`) and move them to the right place.
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.
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.
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.
Ah, okay, well that example makes it clearer. It wasn't clear from your example (or from my local test) where you just show this:
class Todo
# variable defined in class scope
var count = 0
Which compiles into this:
var count = 0;
And also your example page elides the IIFE that your compiler surrounds all output with, implying (falsely) that it's global.
As for ST, I think that for me based on my brief experience, you might want to add more compiler warnings to the watcher. (Basically I messed with Imba locally with two ST windows side-by-side, looking at Imba on the left and js on the right, treating the watcher output as compiler output.) Don't get me wrong, ST feedback is great, but the watcher feels more canonical. Besides, not everyone has ST!
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 :)
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.
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.
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.
Loops as expressions return an array as the value, the page says, but the JS code on the right doesn't seem to show this happening. Which is right? Or does the compiler notice in these cases that the value is not used, and not produce it?
The overview didn't answer my biggest question: what kind of (compile time) type system does it have? Can I use it to get proper type checking, inference and primitive types?
Fun fact: "imba" means "sing" in Swahili, a language spoken in East Africa (Tanzania, Kenya, and to some extent Uganda, Rwanda, Burundi, Malawi, and DR Congo).
Most of it's good, just a cleaner JS, but it'd be better to drop the classes and lambda-type short function syntax in favour of ES6 classes and arrow functions.
I suppose the idea is that 'compile' implies a low-level target whereas 'transpile' suggests translating to another high-level language. I can see some sense in making this distinction.
In the larger linguistics world you have a distinction between "translation" (conversion between languages) and "transliteration" (conversion between forms of a language; cursive writing versus typing versus speech, for instance). I remember this being a particularly important distinction in learning American Sign Language (ASL) because the vocabulary is roughly English-ish it is very easy to transliterate and try to say in ASL an English sentence "as is" without meaningful changes, but just with dealing with the differences between, say, English and Spanish, to speak ASL properly you need to actually translate to more idiomatic forms and abstractions. This is extremely important to ASL not just from a "speak better ASL" standpoint but also because it comes out of a foundational, cultural imperative: ASL was not seen as "a real language" until it proven to some linguists that it validly needed translation, was not just a transliteration of English but in fact a language with its own idioms and grammar requiring translation. This disagreement is so fundamental to ASL also because there was so much pressure from people to "speak real English" rather than develop their own language. There is a transliteration-focused "alternative" to ASL that includes all of the useless English grammar and stutter words like "the" that ASL handles grammatically different, and ASL had to prove its existence against it and also to prove that it was better and also to prove that ASL speakers could still read/write English to work with the rest of the English-speaking country when their native language was grammatically different enough to require translation... It's an interesting cultural battle to read about.
All of which is a long winded example to get back to the idea that the translation/transliteration difference is very similar to the compilation/transpilation difference and while I don't think we've yet seen a cultural battle for supremacy between the terms, I do think there is a usefulness in keeping the distinction. I also see the conversion between idioms/abstractions as being the key difference between compilation and transpilation. Machine language has much different idioms/abstractions from a high-level language; CoffeeScript and TypeScript try to stay very similar in idiom/abstraction to EcmaScript.
Why do people keep throwing around the idea that "X tool is Y times faster than React?" Last I checked no one was claiming React is super fast and I don't know anyone who uses it for its speed. It just seems like such a strange thing. It's like building a new car and claiming it's 100 times faster than riding a horse.
If only horses existed, and you were the first to make a car, would it not be an apt comparison? With performance at 100k renderings per second you don't need to care about keeping the view in sync anymore?
I don't know that I agree with that... a lot of the syntax definitely burrows from Ruby, but then again so does CoffeeScript... this actually looks a lot like CoffeeScript with embedded razor templating.
I think this is either developed by or targeted at people with a ruby background, and does give some context. I'm actually more happy with something closer to JS (EX6/7 transpiling) with React (JSX) than something like this. Usually when you approach headaches on larger teams with JS, it's more that you haven't broken things down as well as you can/should more than a language construct.
JS projects tend to work far better from discrete separations of components, views, functions and composites... simple components can be thought of react components that only use properties for rendering, views are a composition of components that use stores for state interaction. Functions are modules that have singular discrete testable functionality and composites are similar to classes but yeild an object tethered to state/options but mainly glued together from modules that expose a single workflow function.
There's also control/workflow type composition, and node-style object pipes tend to work very well in many of those scenarios... get batch of items from db into an object stream through workflow steps, queues, etc.
It's definitely an interesting abstraction of a few ideas together, I'm not sure what it does in terms of improving a larger workflow. Other than a more wrist friendly syntax.
This tool is forked from Coffeescript, which is deliberately designed to resemble Ruby. There's a good reason for that – some aspects of Ruby's syntax are well-loved.
It might be more effective for you to use your time understanding why these aspects are important, since you apparently feel this project is good, and less time being a bit of a dick about it.
By Ruby programmers. Why is it that Ruby programmers are incapable of imagining anyone doesn't love Ruby?
This isn't a universal truth for all programmers either. I've met plenty Java programmers willing to admit the shortcomings of Java, I've met PHP programmers painfully aware of the language's warts, I've even met Python programmers willing to admit Python's limitations. I've yet to meet a Ruby programmer who doesn't believe that Ruby is the best thing since sliced Jesus.
And clearly other people – or we wouldn't be seeing those syntax elements in other languages.
Why is it that Ruby programmers are incapable of imagining anyone doesn't love Ruby?
They're perfectly capable of that, and I think you've let your own prejudices cloud your judgement.
I've yet to meet a Ruby programmer who doesn't believe that Ruby is the best thing since sliced Jesus.
Hello, pleased to meet you. I'm a mostly-Ruby programmer who is well aware that the language is not suited to every task. Need high performance? Look elsewhere. Need a highly reliable service? Something that would benefit from static typing? Systems-level tools? Same. Ruby is a pain to deploy and has lots of irritating legacy cruft.
What this doesn't mean is that the statement "that pile of junk that is ruby" is anything other than a fucking stupid thing to say.
yeah sure - I was a bit troll-ish in the language. Let me elaborate. Imba is a spin-off of javascript intended for front-end use whose syntax is a mix of coffeescript, jsx and python as well Ruby imho; that said, please name a single use case in which Ruby will be without a doubt the #1 language for performance, scalability and all the other aspects involved in maintaining a business (including availability of programmers). Ruby is only second to PHP, which is just unreedemable (I'm even certified on it... http://www.zend.com/en/yellow-pages/ZEND005898 so don't think I'd refrain from criticizing languages I know, even very well).
As well as by not-Ruby programmers, which is why they keep getting used in non-Ruby languages that don't keep other aspects of Ruby.
> Why is it that Ruby programmers are incapable of imagining anyone doesn't love Ruby?
I think most Ruby programmers are capable of understanding that lots of people don't like Ruby, and more importantly that lots of people don't like aspects of Ruby that those Ruby programmers find most attractive.
Sure, some Ruby programmers have problems with this, but, OTOH, some non-Ruby programmers seem incapable of understanding that other non-Ruby programmers might find some aspects of Ruby attractive that they, themselves, do not.
> I've met plenty Java programmers willing to admit the shortcomings of Java
Well, sure, the more likely you are to be compelled to use a language because of corporate inertia, the more likely people that actually do use it will be the people that don't like it and use it under duress. So I'd expect Java to be among the languages with the highest proportion of active programmers who not only are willing to admit its shortcoming, but who outright despise it.
> I've yet to meet a Ruby programmer who doesn't believe that Ruby is the best thing since sliced Jesus.
Given the number of non-Ruby programming languages created with substantial input from (or even under the leadership of) people in the Ruby community specifically because, while they like many things about Ruby, they find it not optimal for some uses, I think this says a lot more about your limited exposure to the Ruby community than about the Ruby community itself.
> Ruby programmers would stop trying to avoid writing JavaScript by writing their own JS-based implementation of Ruby
I would appreciate it if people knowing very little about programming languages stopped commenting on new languages. Nearly every comment here is either baseless or irrelevant or simply wrong. It's frustrating.
In your specific case: CoffeeScript and this are most certainly not a "JS-based implementations of Ruby." This is: http://opalrb.org/
And how the language "looks" - its syntax - does matter, but not in the way most people think it matters. It's just that the syntactically simpler constructs tend to be used more often, so the choice of syntax affects the code people write. The rest, including "readability" or simply "beauty", is meaningless in the long run.
That's why I said "their own" JS-based implementation.
And the point is that it goes out of its way to re-invent features already supported by ES6 just so they look more like Ruby. Like using string interpolation instead of template strings, for example.
It's not a language built on top of JS to improve upon JS, it's just as contrived as CoffeeScript (which unlike this one actually had a reason to exist in that it influenced the development of ES6 when a lot of features it implemented weren't yet part of JS).
What is the benefit of learning this language? Who is this for? JS programmers? No, they could just use Babel to write something that will eventually become vanilla JS.
Does it bring anything new to the table like ClojureScript or LiveScript does? No, it's basically CoffeeScript with ES6 scoping rules and JSX elements.
So in the end all it adds is another barrier to entry for new developers joining your project/company with the only benefit being that it's "prettier".
I'm not saying bad ideas aren't worth exploring -- they are, and if your bad idea happens to involve creating your own programming language, all the more power to you. But the only "good" reason to use this language is if you want your JS to look like Ruby.
Just like Haml is for people who want their HTML to look like Ruby; and like Sass (not SCSS, I mean the original braceless syntax) is for people who want their CSS to look like Ruby.
Here's a quick (incomplete) list of web innovations you can thank the Ruby community for either popularizing or inventing outright:
* REST
* Many parts of ES.next
* Front-end build tools
* CSS pre-compilation
* JS transpilation
I spent years happily using multi-line template strings while JS developers informed me how idiotic I was for using a transpiler. Since Ruby's goal is to be a language that brings joy to the user, I see nothing wrong with bringing that ethos to other languages. You yourself acknowledge the impact it had on the development of JavaScript.
We in the Ruby community will keep innovating, and you keep hoping that we'll stop, and we'll see which happens.
I didn't claim that the Ruby community invented REST. Rails 1.2 (2006) was the first major web framework to implement it. Do you have any evidence to support your claim that I'm incorrect?
No. Rails populated a form of REST and everybody likes to pretend everything Rails is REST and there are a ton of frameworks trying to imitate Rails' approach to REST but Rails neither invented REST nor was it the one thing making REST popular. It was a major factor, yes, but claiming this purely as an accomplishment of Ruby is silly.
I would be willing to give Ruby the point for MVC because of ActiveRecord but MVC is not synonymous with REST.
> Many parts of ES.next
Again, no. ES.next is nothing like Ruby. Some of the syntax was influenced by CoffeeScript (nobody doubts that -- in fact, TC39 members have explicitly referenced it on more than one occasion) but the features are neither novel nor unique to Ruby:
* The class syntax is pretty much universal.
* The arrow functions are evidently influenced by CoffeeScript but look nothing like Ruby's lambda literals (which are the closest equivalent in Ruby). I think CoffeeScript's use of that syntax was actually pre-dated by C# but I may be mistaken.
* Template strings have no more in common with CoffeeScript's and Ruby's string interpolation than with the same feature in other languages. In fact, if anything, I'd say the interpolation syntax is borrowed from PHP -- but the backticks certainly aren't taken from any of them.
* Symbols are kinda like Ruby symbols if you tilt your head and squint really hard and then only focus on the name and not what they actually are. Again, the concept is neither novel nor unique to Ruby.
* Destructuring and rest/spread operators -- yeah, again, not unique or novel. Plus I think even Python preceded Ruby on that.
* iterators and generators -- again, closer to Python than to Ruby.
* import/export -- just an extension of the ideas of CommonJS which in turn aren't anything like what Ruby has.
* promises -- no, sorry, not Ruby.
* the object literal extensions -- again, not Ruby. Ruby doesn't even have object literals in the sense JS does (which is okay, it doesn't have prototypal inheritance either).
> Front-end build tools
No, seriously not. Yes, rake pre-dates grunt and gulp by a fair amount (as well as jake and other JS-based tools barely anyone seems to use anymore). But it certainly didn't invent them nor was the biggest factor in popularizing them. A lot of build tools before the Ruby (and now JS) toolchains came along were built in things like Java, in addition to the various less formalized build tools written in Python or simply bash.
> CSS pre-compilation
I may give you that. Less pre-dates Sass but started as a Ruby gem. Of course neither of them invented CSS minification and there were attempts at generating CSS before. Compass probably took the crown, though, even though front-end tools in generally have moved on to the Node ecosystem, which seems more appropriate for tools primarily concerned with JS (rather than Ruby, Java or bash).
> JS transpilation
Not really. Java-to-JS transpilation was the original hotness that opened up people to the idea. It was followed by various attempts to port other languages to JavaScript. I agree that CoffeeScript is the first one that gained major traction in the startup scene -- although most teams seem to have realised that the drawbacks aren't really worth it (not just the transpilation but the entire part where everyone has to learn a new language on top of a solid understanding of JS itself).
Yes, CoffeeScript was an important step in the evolution of JS but so were DHTML, pop-unders, JSS and animated mouse cursors and status bars -- and everyone agrees those were a bad idea.
The Ruby community is very vocal and self-important but it's neither as uniquely innovative nor as much of an influence as its members like to make it out to be. If PHP is the kindergarden of programming languages, Ruby is the angsty teenager complaining about how nobody understands them and writing blog posts about their deep insights gained from flipping through Atlas Shrugged.
> It was a major factor, yes, but claiming this purely as an accomplishment of Ruby is silly.
A major factor in popularizing it, as I claimed. Personally, I had never heard of it before DHH's 2006 RailsConf keynote. Could you point me to another web framework that had implemented it before 2006?
> Some of the syntax was influenced by CoffeeScript (nobody doubts that -- in fact, TC39 members have explicitly referenced it on more than one occasion) but the features are neither novel nor unique to Ruby.
Again, CoffeeScript was popularized by the Ruby community, as uptake increased greatly when it became a default in Rails. The syntax was heavily influenced by Ruby, which then found its way into ES.next.
> Front-end build tools
The Rails asset pipeline was actually listed as the inspiration for Brunch, the closest you can get to replicating its functionality in JavaScript. This went a long way towards popularizing the notion.
> I agree that CoffeeScript is the first one that gained major traction in the startup scene
> although most teams seem to have realised that the drawbacks aren't really worth it (not just the transpilation...
Yes, and CoffeeScript first gained traction within Rails. You also seem to be discounting the obvious popularity of ES.next transpilers.
> The Ruby community is very vocal and self-important but it's neither as uniquely innovative nor as much of an influence as its members like to make it out to be. If PHP is the kindergarden of programming languages, Ruby is the angsty teenager complaining about how nobody understands them and writing blog posts about their deep insights gained from flipping through Atlas Shrugged.
> The syntax was heavily influenced by Ruby, which then found its way into ES.next.
I pointed out the major syntax additions of ES6 and to what extent they are based on Ruby or not.
> You also seem to be discounting the obvious popularity of ES.next transpilers.
I'm not. Babel and other "ES.next" transpilers are drastically different in spirit from CoffeeScript. With some exceptions (e.g. JSX and Flow type annotations) most of the syntax it adds to JS are either already part of the language and just not widely supported (i.e. ES2015) or experimental proposals for new language features intended to eventually land in a future JS spec.
CoffeeScript doesn't work because it requires you to learn a new language on top of JS. ES.next works because it's bleeding-edge JS (plus some speculative additions). The code you write for Babel today will likely run without transpilation in a JS environment a year or two from now.
This is a general trend in web technologies. CSS pre-compilers like Sass are being replaced or enriched by CSS "post-compilers" like postCSS (that consume vanilla bleeding edge CSS and spit out CSS that works today). JS transpiler languages like CoffeeScript are being replaced by ES2015 (and speculative ES.next) with compilers that translate the code to JS that works today (or yesterday, even -- Babel generally works fine with IE8/ES3 if you use the necessary shims and shams).
Your point is that Ruby's role to all of the developments you mention is essential and unique. I'm arguing it's not. By far.
The only remarkably unique thing about the Ruby community I keep noticing as an outside its rise and fall of the Brogrammer culture and the aftershock we're still experiencing to this day. But even that, I think, would have happened even if Ruby never existed.
> CoffeeScript doesn't work because it requires you to learn a new language on top of JS.
The folks that have been quietly productive with CoffeeScript for years, and have and continue to make millions of dollars because of it, would likely disagree with you on that point.
> Your point is that Ruby's role to all of the developments you mention is essential and unique. I'm arguing it's not. By far.
> The only remarkably unique thing about the Ruby community I keep noticing as an outside its rise and fall of the Brogrammer culture and the aftershock we're still experiencing to this day. But even that, I think, would have happened even if Ruby never existed.
Well, you've failed to sway me on that (by far), and the clear chip on your shoulder you have regarding the Ruby community as a whole leads me to believe your vociferous arguments to the contrary might be motivated by something other than your desire to spread the truth.
Right you are! I didn't realize it had beaten Rails to the punch by a year. But yes, I will stand by my claim that Rails was responsible for popularizing the notion in the wider web development community.
You never said anything about web framework before, you said MVC. That's a different discussion. Although we were using MVC in Struts 1 back in what, 2001?
How about the whole WSDL/SOAP services that appeared way before that? You're telling me that Rails was the one who came out with the modern REST ideas?
That's total tech illiteracy right there. Damn, you even had the nerve to defend that feeble argument.
WSDL/SOAP are not REST. I'm telling you that REST was popularized by Rails, because it was the first major web framework to use it. You've yet to refute that argument, but you do continue to be rude, so have a good one!
Well if you define REST as "Web Apps developed with RoR" then I guess you're right, Rails is definiteley the pioneer of Rails development.
>You've yet to refute that argument
There was (at least) Tomcat deployed and quite popular, and yep, everything moved through REST interfaces. Even with that one and the huge success it had in the enterprise world, I wouldn't dare to say that the success of REST relies on Tomcat anyway.
REST hit it big with the www, www is REST's killer app. Those things are quite literally the first ones you should know when you start developing for the web.
The funny part is that technically Rails and Rails-inspired REST frameworks get it wrong. They're just exposing the server-side models via REST interface and the server-side models in turn expose the database's tables. That's REST by the books but not particularly useful unless all you're interested is exposing your database tables to the clients.
Automagic REST APIs may be easier to do with "RESTful" MVC frameworks but what you really want is a domain-oriented REST API. But I digress.
Here's a handy test to determine if two technological terms mean the same thing: are they used interchangeably? If I said to someone, "oh that looks like you need a SOAPful interface," would they assume that I meant RESTful? Probably not, since they're two different technologies. The move to REST was actually inspired by the perceived deficiencies in WSDL and SOAP.
> The funny part is that technically Rails and Rails-inspired REST frameworks get it wrong.
Well, that's a bit tangential to my original point. I wasn't claiming that you specifically liked the way it was implemented, just that Rails, and thus the Ruby community, was responsible for its popularity. Despite the length of this thread, neither of you has managed to debunk that claim with anything resembling evidence.
Find a reference to Tomcat using REST before 2007, and give us the link. I'd bet you can't, since Rails was the first major web framework to implement REST.
> REST hit it big with the www, www is REST's killer app.
Since REST was invented in 2000, and the web itself had been around for a bit before that, I fail to see how this could be true.
"The first edition of REST was developed between October 1994 and August 1995, primarily as a means for communicating Web concepts as we wrote the HTTP/1.0 specification and the initial HTTP/1.1 proposal. It was iteratively improved over the next five years and applied to various revisions and extensions of the Web protocol standards."
- Roy T, Fielding, Architectural Styles and the Design of Network-based Software Architectures, 2000
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