-
Notifications
You must be signed in to change notification settings - Fork 6
Coming from JavaScript
ES6 adds a lot of nice things to JavaScript, but didn't address JavaScript's three biggest shortcomings:
- It dramatically reduces the number of tokens required to code.
- It ensures everything returns a value so you can program in a functional way.
- It avoids JavaScript's pitfalls:
- JavaScript's == and != are dangerous. CafScript compiles == and != into ===, and !==.
JavaScript should be considered a machine-language. It is more machine-friendly than human-friendly. And that's great! Like the JVM, it's a runtime that is available on all platforms. Even better than JVM byte-codes, Javascript is vaguely human-readable. As such, it's easy to inspect the generated code and see what's going on under the CaffeineScript hood.
I strongly believe 'less is more.' Given that, it's no surprise I think JavaScript's syntax is horrible. We can do so much better:
# CaffeineScript - 19 tokens including only 2 must-match-tokens: #{ and }
import &MyFramework
class HelloMessage extends Component
render: ->
Div "" Hello #{@props.name}.
render HelloMessage name: :Bob// ES6 - 55 tokens including 22 must-match-tokens: 5x(), 3x{}, 1x${}, 1x`` and 1x''
var {createFactory, render, Div} = require('MyFramework');
var HelloMessage = (class HelloMessage extends Component {
render: () => Div(`Hello ${this.props.name}.`);
}).createWithPostCreate();
render(HelloMessage({
name: 'Bob'
})); It's hard to overestimate the negative impact of language built on first-class-functions that contains so much non-functional syntax, i.e. syntax that doesn't return a value:
- functions don't return a value unless you manually add 'return'
- Some of the many constructs that don't return values:
- if statements
- try statements
- switch statements
- while and for loops
Does programming JavaScript feel like living a SpaceQuest Adventure? CaffeineScript follows CoffeeScript's lead and takes it one step further: almost all of JavaScript's nasty little surprises, mostly due to coercion, are prevented with CaffeineScript.
I'm not the only one to notice these ;). Here is a good list from Oreilly.com's JavaScript Book:
- '==' means JavaScript's '===' (and '!=' is '!==')
- Truth is Ruby-style: only false, null and undefined are falsy (COMING SOON)
- interpolation converts arrays, null and undefined to useful strings:
- "#{[1,2,3]}" == "123"
- "#{undefined}" == ""
- "#{null}" == ""
- Throw errors from within expressions.
- Certain keywords are statements only - they can't be used in an expression. Ex: foo ? throw new Error : 123. There is absolutely no need for these limitations.
- No crazy missing-semicolon problems due to semicolon-insertion
- Automatic block-scoping
- No implied globals
- Loops, comprehensions as well as functions define scopes.
- Variables are automatically declared with "let" in the most-specific scope in which they are assigned.
- All reserved words can be used as property names just like any other word: (COMING SOON)
- foo.case == foo['case']
- Sane replacement for typeof (COMING SOON)
- All switch-cases are all automatically terminated with 'break'.
- No function hoisting; all functions are defined in expression-form, not statement-form.
- undefined vs null
- Undefined is an unfortunate concept. The semantic difference between undefined and null is negligible. Having two values for non-values is confusing and causes subtle bugs.
- I'd like to reduce the usage of undefined, but unless we have operator-overloading, using 'null' everywhere may cause as many new bugs as we fix. For example: "null >= 0" is, incorrectly, true in javascript, but "undefined >= 0" is, correctly, false. Until we can efficiently overload the meaning of >=, CaffeineScript will return undefined in all the places CoffeeScript does.
- Efficient operator overloading may be possible. If so, we can fix all the surprising, overloaded arithmetic operators and comparison operators:
- "2" + 1 == 2 + "1" == "21"
- "2" > 1 == true
- null >= 0 == true
Solvable with CaffeineScript:
- () => {} functions don't have 'arguments' but functions(){} do. I object to this introduction of inconsistencies, but I'm OK with deprecating arguments now that we have ... notation. (COMING SOON: 'arguments' should be illegal)
- class limitations don't allow statements or defining value properties. CaffeineScript solves this by moving all the class definition except the constructor out of the JavaScript class-definition-block.
- Class-declaration, like function-declaration, has two identical yet semantically different forms: statement-form vs expression-form. In the former, you can't declare a class with the same name twice. In the latter, it's OK. CaffeineScript only generates expression-form.
- [a, b...] = c is OK, but [a..., b] = c is not. CoffeeScript solves this. CaffeineScript doesn't right now, since it's considerably more work to do the second case - since ES6 doesn't support it.
Probably not solvable with CaffeineScript:
- There is no way to declare a Class with a runtime-generated-name.
- Class functions cannot be invoked, but they are still typeof "function". WTF. Really. If they were changing the semantics anyway, either just make them typeof "class" OR, make invoking the class-function trigger a different method than constructor, the problem they were presumably trying to solve. It would be awesome if we could provide a custom method for invoking: MyClass(). This would be an excellent way to implement the factory-pattern popular in frameworks like React.
- There is no way to detect if an object is a class other than the ridiculously inefficient: /^class/.test(). Typeof is 30x faster: jsperf.
- Iterators return a new object for each iteration. My experience is Javascript's most difficult performance challenges is creating too many objects and overloading the GC. Maybe optimizes magically avoid the object creation, but in my experience they don't tend to do a very good job of that. If not, iterators in JavaScript are useless whenever performance matters.
- Iterators are 10x slower than normal loops: jsperf
- Home
- Get Started
- Benefits
- Highlights
- Productivity by Design
- CaffeineScript Design
- What is CaffeineScript Good For?
- Get the most out of JavaScript
- Language Comparison
- CHANGELOG
- Blocks Instead of Brackets
- Binary Line-Starts
- Everything Returns a Value
- Streamlined Modules
- Scopes and Variables
- Optional Commas
- Semantics
- Ambiguities