Hacker News new | past | comments | ask | show | jobs | submit login
Spider Programming Language (spiderlang.org)
117 points by alongub on Nov 17, 2014 | hide | past | favorite | 82 comments



> CoffeeScript (and its derivatives: LiveScript, Coco, etc) have serious issues of ambiguous code, alien syntax and scoping problems.

How long will programmers think of "alien syntax" as a problem? I don't understand it at all - syntax should fit the problem domain and language semantics first and foremost, NOT expectations of programmers writing in other languages. It makes absolutely no sense - from a language design perspective - to invent a new, interesting language and then try to fit it into some "standard" syntax. In my mind this misses at least half of a point of creating a language in the first place!


IMO, the bigger complaint about CoffeeScript is ambiguous syntax - the syntax tree is very sensitive to even the smallest whitespace changes.


Exactly. Syntax style is usually a matter of personal opinion. "Alien syntax" wasn't very objective and I should probably remove it from the website.

However, ambiguous syntax is a huge problem of CoffeeScript. Read more here: http://ceronman.com/2012/09/17/coffeescript-less-typing-bad-...


> However, ambiguous syntax is a huge problem of CoffeeScript.

Actually this is also a matter of personal opinion. As the author himself notes in the conclusion:

"The problems described here might not apply to you if you come from a different background. I come from Python, C# and C++. But if you come from Ruby or Perl, you might think these are not problems but actually cool features."

Personally I don't mind, but at least I can agree that Coffee syntax is ambiguous and can be bothersome sometimes.


Yes, CoffeeScript syntax is often ambiguous, but you learn a few simple rules [1] and ignore darker corners.

And I think slightly ambiguous transpiler is okay when the resulting language is not ambiguous. You can always check the output (which is very readable).

[1]: For example, "[t]he implicit call wraps forward to the end of the line…"


But there is no problem: "programmers writing in other languages" - they will keep using those other languages, while you will use your new language with unusual syntax. Alone.

Now if you want to persuade those other developers to use it, then maybe you should meet them half-way?


You're assumming that programmers will only switch languages if they already "know it". What about other benefits to other languages, such as different paradigms, type systems or other semantic features? Surely to someone who actually writes code they're just as important as the syntax?


> Surely to someone who actually writes code they're just as important as the syntax?

They're more important. I don't switch tools just to get better syntax (unless the syntax is really horrible). I switch to get a tool that will do something different, or do the same thing better.

So: Don't switch syntax just to switch syntax, and expect anybody to care.

On the other hand, things that are really different but have the same syntax can be confusing. You subconsciously expect it to work the old way, and it doesn't...


I'm still a bit unsure about these sorts of projects. I like the idea of improving Javascript's rough edges, but whenever I start a new project, I always seem to stick with plain old javascript.

That said, Spider feels like it is heading in the right direction:

- It embraces JS's prototype OOP. I've never liked how CoffeeScript tries to add traditional classes. Not sure the syntax is right, but I appreciate the goal.

- It adds just enough "modern" features and syntax to feel like Javascript without requiring me to learn a whole new language.

Feels like modularity is missing, though. Is there any support for "require" or "import" or something similar?


I'm still unsure how to add modularity while maintaining compatibility with CommonJS, AMD, etc.

I thought about adding a require statement such as:

    require "vm"

    require (
      "util",
      "io"
    )
That would also support git repos, inspired by DuoJS (https://github.com/duojs/duo):

    require "alongubkin/phonertc"


> Feels like modularity is missing, though. Is there any support for "require" or "import" or something similar?

I haven't personally tested it, but i imagine everything is supported, including require and import. It doesn't look like Spider does anything weird to scoping, so to use a global you simply use it with `::global(foo)`, or `use global; global(foo)`

I imagine require would be `use require; require('mylib')`, and etc.


Of course, but I think he meant native modularity support, which is important IMO.


Isn't that a huge problem to solve though? I don't think i've seen a consistent model for this that suppots both Browser and Server(Node). Node is simple, but Browser has a lot of possible implementations, and a lot of preferences from userspace on how it should technically be implemented.

Ie, i have a strong dislike for how RequireJS handles this. I much prefer simply embedding with Browserify and the like.

How would you handle this issue, i wonder?


This is a huge issue, and I'm still thinking about it. That's why I didn't add native require support yet. I'm hoping that the community would come up with a good idea.


I think you should stay far away. It's a solved problem.


Welcome to the fray. I kind of like that there are so many JavaScript wrapper languages turning up. It allows for cross-pollination of ideas and hopefully in the long term those that work the best for people in practice will establish themselves a niche.

That said, I don't think this is the one for me.

I think I would lean towards halfway between Spider and JavaScript

I'd prefer to keep some bits from Javascript

* function instead of func.

* bracketed if and while conditions.

* no list comprehensions (but I could just choose to ignore).

* no ranges (unless only in case conditions)

* not sure about # for int div.

From spider I'd keep

* Default parameters

* splats

* ?

* ??

* * *

* logical operators

* for loops (but bracketed)

* extends and super.

and I'd add sugar.js http://sugarjs.com/ as standard


I'm always curious why people don't like list comprehensions - care to expand on that?

I'm also the opposite of you on `function` vs. `func` - I think `fn` would have been even better! The verbosity of `function` is one of my least favorite things about javascript. It seems superficial, but I think it makes it noticeably more awkward to program more functionally.


I've used list comprehensions in Haxe, but not much more than in tests to try them out. I haven't yet had an opportunity to use them as best solution for the job.

It's not that I'm against either func or comprehensions in principle, it's more that they are a departure from JavaScript. My preference would be for a JavaScript[FIXED] than a complete style change.

For something with "all the features" that compiles to JavaScript I prefer Haxe, but for something that has squishy dynamic and prototypey feel of JavaScript (which spider seems to be going for) I think I would want it to resemble JavaScript a bit more, if for no other reason to pretend that they got it right the first time.


I never mind verbosity in a programming language. Making things succinct at the expense of readability is a poor choice in my mind. If you don't like to type, any decent IDE can fix that for you.


But list comprehensions make things both more succinct and more readable.

Compare: "Give me one scoop of ice cream of each kind that is chocolate-flavored."

...to: "I would now like you to prepare for looking over the ice cream flavors, and also to prepare a new list which I will later fill in. Consider the first ice cream flavor. Is is chocolate? If that is the case, I would like ... once that is done, consider the next flavor ... now add this flavor to the end of the list which we prepared earlier ... consider the next flavor..."


I didn't complain about the amount of typing. Programming involves so little typing in general that bringing it up is always a red herring. I often don't mind verbosity in a programming language, but not never. The distinction is basically verbosity that makes common patterns noisy to read. The `function` keyword is that sort of verbosity in javascript. I think explicit returns are also that sort of verbosity in javascript. The language lends itself to using lots of anonymous functions, but because of the `function` keyword and implicit return, anonymous functions are very noisy. It doesn't help readability, it just results in long lines or stacks of lines to express simple concepts.

I find this type of syntax discussion pretty superficial, but, for better or worse, syntax has a big impact on how programs are written in a language.


fn is a often used as a variable name


It wouldn't be if it were a keyword! More seriously, there's plenty of precedent for using `fn` and people get by just fine. (I don't think `func` is a bad choice either, my preference for `fn` was just a completely irrelevant aside.)


Nice! I started on something like this a while ago: https://github.com/vinodkd/betterscript.

You have a slightly larger goal - a better js with some useful syntax from other languages/efforts. Mine was just a better javascript.

But: I did have a module syntax. No plug here, btw; feel free to borrow any/all syntax and kudos for getting it done:)


This is exciting. I've been experimenting with languages to replace JS with, and have only liked Rapydscript so far (due to an existing familiarity with Python).

Syntactically, I see some inspiration in Spider from both Python and Go. As this is still in alpha stages, any chance you'll remove the semicolons? That would push the syntax into "beautiful" realm for me.


This is definitely possible. Can you open an issue in GitHub?


I'm sure you are well aware of this, but just to be safe: Go has more sensible semicolon insertion rules compared to JavaScript, avoiding pretty much all issues JavaScript has with it. Be sure to take a look at it!


Of course. Swift does this as well BTW.



The only thing i don't like so far, is `func` and `->` both expressing functions. I use Coffee a ton, and Golang, so oddly enough i love both syntaxes.. but i don't like multiple ways to declare a core feature like functions.

Just my 2c.

Fwiw, i'm going to be trying this out asap - I have high hopes for this replacing my very heavy CoffeeScript usage!


I think it's quite good - it allows a programmer to conceptually separate her "normal" functions from lambda expressions, even if they're essentially equivalent, and one is syntactic sugar for another.


It's not duplicate syntax. `func` adds a named function to the current environment, and `->` only describes an anonymous function. It's the equivalent of `function foo(...)` vs `function(...)` in JS.


Can you not `func(foo){}`? Because that is what would bother me.

`func(foo){}` and `(foo) ->` seem too similar, for my taste at least. Sure, the difference is that one is always anonymous, where as one is sometimes anonymous.. but we've been using `function` as both named and anonymous for ages


ES6 already has =>, I think that Spider should probably stay far away from trying to replicate existing language features with different syntax


Many functional languages have shortcut syntax for inline functions, e.g. in OCaml:

  let f = fun x y -> x + y
Haskell:

  let f = \x y -> x + y
It looks that Spider uses a similar syntax, but uses uncurried form in line with function invocation syntax.


I actually agree about this - two ways to do exactly the same thing is generally a bad thing when it comes to language design. But I think that a more important goal is to make the transition from Spider to JS as easy as possible.


I'm worried by the focus on OOP in the examples. I hope that OOP is not a focus in the language. This nice and simple enough of a language that I could see JS people getting on board, and using this for real JS stuff.

I'm afraid that an inordinate focus on OOP will alienate JS devs, who are already good at writing in a functional style and don't need it.

The people who will appreciate the trappings of OOP are more than likely the typical classically trained programmers, who will write 300 lines of Spider on the frontend of their Python hobby project, and not touch it again.


Can't agree with your implication that 'real JS stuff' won't get done and 'JS people' won't get on board due to its 'focus on OOP'.

I've yet to see a large JS app written in a 'functional style'. Most large client-side apps I've come across are written in Backbone, Angular, Ember etc. which are all frameworks/libraries that embrace OOP.

You shouldn't mistake JavaScript's 'prototypal' nature for it being a non-OOP language. JavaScript and OOP are a very good fit.

> The people who will appreciate the trappings of OOP are more than likely the typical classically trained programmers, who will write 300 lines of Spider on the frontend of their Python hobby project, and not touch it again.

If you're really dismissing __all of OOP__ to that extent I feel like you are seriously misunderstanding OOP and I highly recommend you read/watch at least:

- POODR by Sandi Metz [1] - Explores OOP, SOLID principles, testing, more. The best book on OOP I've ever read. Ignore the fact the code examples are in Ruby (by that I mean, they're easy to understand).

- Refactoring by Martin Fowler [2] - The definitive refactoring book... which goes hand in hand with OOP.

- Boundaries (Talk) by Gary Bernhardt [4]. He talks about the 'functional core, imperative shell' pattern of software architecture that acknowledges the fact that some form of OOP/procedural/imperative programming is unavoidable. It's a great talk.

Outright dismissal of OOP really has no place in modern programming. Even if you get into functional languages like Clojure you'll find they're actually embracing a lot of OOP ideas [3], even though they pretend they're not into it :)

[1] http://www.poodr.com

[2] http://martinfowler.com/books/refactoring.html

[3] http://www.youtube.com/watch?v=13cmHf_kt-Q

[4] https://www.destroyallsoftware.com/talks/boundaries


Thanks!


Definitely not the focus! The extends/super keywords are just "shortcuts" to normal prototypal inheritance. I just thought that the time machine example was pretty cool :)


Yep, same as CoffeeScript.

All CoffeeScript's `class` stuff does is set up the prototype chain for the exact way that every JS dev under the sun does their manual prototype stuff.

AFAICT you're doing the same thing you're just making it look more function-y. Not that I hate that I just think it's an incredibly minor semantic difference, and I probably slightly prefer the outright 'call it a class' approach of CoffeeScript as it feels more like calling a spade a spade.


i'm always curious, why keep brackets? if blocks can be implied by whitespace (that vi can handle for you), what do explicit brackets buy you in exchange for the time it takes to type them?


Explicit delimiters compose inside expressions much more gracefully. This is the main reason Python doesn't allow multi-line lambdas: if you have some significant indentation inside another expression, it's hard to tell how the rest of the expression following the unindent should be formatted.

CoffeeScript does handle this, but I've always felt it was a murky corner of the grammar.


You can easily allow both, though. At worst you can simply turn off significant indent inside explicit delimiters.


Sure, but then you need to implement both ways to express the same thing, and then deal with the infinite arguments it will spawn between proponents of each camp.


Typically, what I do is just map the indent and dedent tokens directly to some suitable bracket pair, so the implementation is trivial.

As for the infinite arguments, well, as a language designer, is that really your problem? I mean, that kind of stylistic argument is no different from the endless arguments about bracket placement in C-like languages, or comma placement, "a+b" versus "a + b", and so on. People quibble about the dumbest things, I say just let them.


I can't tell you how many times my IDE has "helpfully" tried to autoindent my CoffeeScript for various reasons. In CoffeeScript, if your indentation gets thrown off, your code is going to do something completely different. That's why I'm very appreciative of languages with brackets.

I know in CoffeeScript I could use parentheses to surround indented parts (because everything is an expression), but it just looks wrong when I do it. I wish CS treated parentheses and curly braces as interchangeable in most cases, which they pretty much are.


Easy copypasteability. Yeah, I don't understand why this would be an advantage either, but that's an argument I see most often.


Kudos to the creator. Writing something like this takes a lot of effort and it looks like they did a great job! Well done!

With that said, on wider level, what's the allure of these JavaScript replacement languages? Is JavaScript syntax really that difficult for some developers to wrap their head around? I can understand something like Dart that has an underlying goal of performance, but the purposes of things like this or CoffeeScript genuinely confuse me.


It's not that JavaScript syntax is difficult. It's that there are some common patterns that repeat themselves so much times.

For example, safe object navigation. This code in Spider/CoffeeScript:

    var x = a?.b?.c?.d;
compiles to something like:

    var x = typeof a !== "undefined" && a && a.b && a.b.c ? a.b.c.d : void 0;


You can also handle problems like this via libraries. For example, underscore-contrib [1] does it this way:

    var x = _.getPath(a, "b.c.d");
There are definitely advantages to having this pattern baked into the language, though.

[1] http://documentcloud.github.io/underscore-contrib/


I've been using node-jsx and jsx-loader to bring JS Harmony syntax into projects I'm working on now. The last great hurdle to make JS a language that's easy to express in is the existential operator. It sucks how often you have to manually null-check in JS.

I'm mighty tempted to write a Webpack plugin to make `?` usable in vanilla JS.


Another reason to prefer CoffeeScript is because of its low cost of both defining and calling functions. The combination makes functional programming, including working with callbacks and promises, much less of a headache.

Even if you don't know CS very well, I dare you to take a look at the JavaScript this compiles to and call it more readable:

    (req, res)->
      getUserIds(req.query)
      .then (ids)->
        Promise.all ids.map (id)-> 
          getUser(id).then (user)-> user.friends.count
      .then (response)-> res.send 200, response
      .catch (error)-> res.send 500, error


I believe your example is a perfect demonstration of how coffeescript can cause unintended bugs.

You code compiles to:

  (function(req, res) {
    return getUserIds(req.query).then(function(ids) {
      return Promise.all(ids.map(function(id) {
        return getUser(id).then(function(user) {
          return user.friends.count;
        });
      }));
    }).then(function(response) {
      return res.send(200, response);
    })["catch"](function(error) {
      return res.send(500, error);
    });
  });
Not what intended, I assume :)


Well, that's definitely the JavaScript I intended to create :) Is there a bug in my logic somewhere?

Edit: But that aside, to be fair, I'll readily agree that it is easy to mess up CoffeeScript's significant whitespace if you don't pay attention to it. For example, you add a multi-line callback to one of those single-line callbacks at your peril!

But the tradeoff is, no mismatched braces/parenteses. Personally, I find the warts are not that hard to avoid, and the overall impact on my productivity is positive.


I guess he's referring to the implicit returns which are a pain in the neck to deal with.


Implicit returns are the norm in ES6's arrow functions. I use CoffeeScript for most of my personal coding, and I can think of exactly one situation where an implicit return got me in trouble. Generally, if you don't care enough about what your function returns to check it, then it's likely the calling function doesn't either, assuming you're familiar with the particular API you're working with.


In LiveScript there's syntax to explicitly omit any return value, it's just a function with !-> instead of -> for the arrow.


That's a question of perspective, I think-- if we're calling this function from somewhere, and we care about what it does, we need those returns.


I doubt anyone will see this, but just for posterity: Still not seeing a bug in this code, and under the tentative assumption that none exists, I find it amusing that you were confused by what you think is the more readable version :)


More concise? Yes.

More readable? Eh...

I can grok either at about the same speed.


That's fair. Personally, I spend a lot of time reading and writing JavaScript, and I still can't not find all the braces distracting.

I mean, if you're talking about a deep understanding of what the code does, I agree with you. But when you're writing a lot of code that basically looks like that, it's useful to be able to take it in at a glance.


The main reasons I reach for Coffeescript for my personal projects are: * built-in support for comprehensions and other array/object operations * simple syntax for context binding * automatic module isolation. These eliminate a lot of boilerplate littering my JS code. At my company gig we use JS but rely heavily on Underscore to address the same pain points; I prefer to have it built into the language syntax instead. ES6 probably has enough of this built in to make me switch back eventually.


It's relatively easy to build a compile-to-js language because of the pre-existing tooling.


One thing for sure is apparent in the new Javascript movement is that every framework tries to script your Javascript and not be Javascript. Nothing against experimentation and there are merits to generation to target platforms, but this is a common theme.

The NBL is Javascript yet everything to support it moves away from it? Very strange, do people hate Javascript that much?

Try my new scripting language, it will help you script your Javascript.


This looks to be an implementation of the concepts (but not the language) proposed in http://www.walkercoderanger.com/blog/2014/04/what-coffeescri.... Several of the terms used are exactly the same.


Spider was highly inspired by this article. In the original "Introducing Spider" article I wrote, I referenced it


Is backward transliteration from pure JavaScript to Spider possible so that one can deal exclusively with Spider and not have to learn JS in order to deal with other people's code?

If one must know both in order to be an agent in the real world then its utility is somewhat limited.


Interesting comment; it seems to imply that some people will learn Spider before JavaScript. Whenever I come across one of these compile-to-JS languages I take it as "this makes you more productive, as long as you've learned JS first and understand the mapping".

Spider does look like it would actually be a really cool first language to learn!


> Is backward transliteration from pure JavaScript to Spider possible

Yep, this is important to avoid the "Groovy" problem where Groovy is valid Java, except for lots of little cases where it isn't, e.g. == behaves differently, default member access behaves differently, etc etc. Since Java 8 lambdas, Groovy is now wildly different in its syntax.


'Fraid I don't understand your response. What is Groovy and what has it to do with Spider?


Groovy is a JVM language which is dynamically typed (a la python and ruby). It never really took off, partly because you had to understand java (and the JVM) pretty well in order to do anything other than trivial scripts with it.

The point being made is that if Spider wants to take off, it had best not require an intimate knowledge of javascript - and we can look to groovy to see what happens otherwise.


    Additionally, loose typing can be one of JavaScript's best features if used correctly.
For me, this is by far the worst feature of JavaScript.


The website states that Spider is still a work in progress. How complete is it at this point? Is it usable for hobby projects at this point in time?


Hobby projects - definitely, but I wouldn't use it for production projects yet. Even though Spider currently has 92% test coverage, I believe Spider still needs more testing and feedback.

Make sure to report any bug you encounter so I can fix it as quickly as possible!


Awesome, thanks. I'll see if I can squeeze in some time to poke around at Spider, (I'm sure you understand how hard it can be to prioritize hobby projects :) and I will definitely file any bugs I come across.


Neat! Did anyone make a grunt plugin yet? :)


You are welcome to make one! :)


I've never built one before, but here's my first attempt: https://github.com/mariusc23/grunt-spider-script

Let me know if you notice any issues!


I'm sorry but the syntax is absolutely gash! This is like a horrible lovechild between Python and Coffeescript gone terribly terribly wrong. If that was the selling point then its a no go from me. I know this sounds harsh but I actually thought that this was a language to create web crawlers.

  func TimeMachine(pilot) {
  this.pilot = pilot;

  this.go = func (noise) {
    ::console.log(noise);
  };
  }

  func Tardis() 
  extends TimeMachine("The Doctor") {

  this.go = () -> 
    super.go("vorp vorp");
  }


Appreciate your opinion!

About the :: syntax: http://spiderlang.org/#code-safety-global-scope-usage

About the extends/super syntax: http://spiderlang.org/#functions-inheritance


If it's any consolation, I think spider uses the most sane syntax out of any compiles-to-JS language I've played with so far. And that's coming from an arachnophobe :)

Maybe because I've written a decent amount of C++ I'm more acclimatized to the "::" syntax..




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: