batiste / CokeScript

CokeScript is a whitespace sensitive language that compile to JavaScript
42 stars 5 forks source link

Feature request: Arrow instead of def keyword, Babel by default, IIFE creation in loops #2

Closed m1sta closed 9 years ago

m1sta commented 9 years ago

Just throwing this all out there for discussion.

I'd love to see CokeScript evolve to be a wrapper above Babel so that we basically got ES7 (or whatever Babel is able to support) but with more terse and more easy to read syntax.

Being able to conciously grab one compliation package would be great. Especially if the result is that any normal javascript would work fine, plus there are a few little shortcuts that can be included too.

The things that jump out in my mind..

    let example1 (callback) ->
        try 
            let dataToStore = JSON.stringify(hello:'world')
            await db.put(id: 123, data: dataToStore)
            let resultString = await db.get(id: 123)
            let resultJSON = try JSON.parse(resultString) catch resultString
        catch (err)
            if (err.status !== 409) throw err;
       finally
            callback(err, resultJSON)

    let example2 ->
        let funcs = {}
        for (i in 1,2,3) funcs[i] = (msg, #i) -> msg + i
        for (key, value in funcs) 
            let expected = "Value should be " + key
            let actual = value("Actual value is ")
            console.log(expected, actual)

I'm personally not a fan of automatic variable declaration outside of for loops and try/catch/finally combinations, makes picking up typos more difficult, and classes and array destrucuring are part of the new JS spec. I left these out deliberatley.

batiste commented 9 years ago

In the contrary I find it refreshing. Look at the code of the compiler itself (there is a syntactic coloration file for sublime in lib/). The absence of any let/var is quit a big win of this language in my book.

It would be nice to see some of these points detailed in their own ticket and I encourage you to do so. In the other hand it seems you want to change the language so much it wouldn't quite look like the original design at all. I am not sure all the changes you want are compatible although I am very open to change things especially now that the only software written in CokeScript is the compiler itself.

Cheers

m1sta commented 9 years ago

Thanks Batiste for replying.

Referring to this: http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example, I'd imagine that...

var funcs = []
for (var index = 0; index < 3; index++)
   funcs[index] = (#index) -> console.log("My value: " + index)

would complie to this...

var funcs = [];
for (var index = 0; index < 3; index++) {
    funcs[index] = (function(index) {
        return function() {
            console.log("My value: " + index);
        };
    }(index));
}

The hash symbol indicates a parameter that should pushed into an IIFE to ensure that it the required closure is created. In my head I think of it as a 'lock' symbol. Similar in concept to Coffescripts do but with an, imho, easier to understand syntax.

m1sta commented 9 years ago

Appologies, I edited my original comment while you were obviously in the midst of replying.

The rational for the automatic function decoration stuff is conceptually along the same lines as the multpurpose for-in that you've already got.

The promises stuff is in recognition of the fact that people will be writing stuff like this a lot now that promises are formally part of the javascript spec...

function get(url) {
  return new Promise(function(resolve, reject) {
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      if (req.status == 200) {
        resolve(req.response);
      }
      else {
        reject(Error(req.statusText));
      }
    };
    req.onerror = function() {
      reject(Error("Network Error"));
    };
    req.send();
  });
}

we could make it look more like...

getUrl = (url) ->
    req = new XMLHttpRequest()
    req.open('GET', url)
    req.onload ->
        if (req.status == 200) resolve req.response
        else reject Error(req.statusText)
    req.onerror -> reject Error('Network Error')
    req.send()

In the end CokeScript ends up generating a few different function types...

m1sta commented 9 years ago

If inferring the function type (generator, promise creating, async etc) is too difficult, which I'm hoping it's not, then being able to simply write fn = async(a,b) -> await a.get(b) and fn = generator(a,b) -> yield a + b and fn = promise(a,b) -> resolve a + bmight be an option.

I prefer the more concise code with the function type inference but I can see an argument for this approach. It's easier on the parser and it makes it very quick to see the type of function that you're working with.

m1sta commented 9 years ago

On the absence or inclusion of let/var outside for loops and catch statements, I think it'd be great to see them not required by default, but if you use them in a scope, you need to use them everywhere. Ie. inclusion of the let or var keyword anywhere in the scope block switches off general purpose automatic variable declaration (which is on by default)

batiste commented 9 years ago

I like the conciseness of this:

req.onerror -> reject Error('Network Error')

Although I think it would be better to have

req.onerror -> reject(Error('Network Error'))

I really dislike optional parenthesis. My brain cannot parse the code without it.

m1sta commented 9 years ago

I totally agree. I hate optional parenthesis too. One of three things that really bug me about coffeescript. I was actually thinking of a keyword at the time but in retrospect it was just stupid. req.onerror -> reject(Error('Network Error')) is better. reject and resolve should are a little like arguments or this in my head (ie. they're not explicitly defined and they can be re-assigned).

This is actually where my thinking has evolved to over the last couple of days: https://gist.github.com/m1sta/218b793d105a5590bc85. Realistically it's looking more like an evolution of coffeescript than anything else. With the exception of the whitespace->brackets conversion the rest can probably be implemented in sweet.js macros.