The Spider Programming Language
spiderlang.org
spiderlang.org
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!
However, ambiguous syntax is a huge problem of CoffeeScript. Read more here: http://ceronman.com/2012/09/17/coffeescript-less-typing-bad-...
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.
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…"
Now if you want to persuade those other developers to use it, then maybe you should meet them half-way?
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...
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 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"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.
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?
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 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.
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.
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 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.
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:)
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.
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!
`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
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'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.
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 :)
[2] http://martinfowler.com/books/refactoring.html
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.
CoffeeScript does handle this, but I've always felt it was a murky corner of the grammar.
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 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.
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.
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; var x = _.getPath(a, "b.c.d");
There are definitely advantages to having this pattern baked into the language, though.I'm mighty tempted to write a Webpack plugin to make `?` usable in vanilla JS.
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, errorYou 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 :)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.
More readable? Eh...
I can grok either at about the same speed.
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 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.
If one must know both in order to be an agent in the real world then its utility is somewhat limited.
Spider does look like it would actually be a really cool first language to learn!
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.
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.Make sure to report any bug you encounter so I can fix it as quickly as possible!
Let me know if you notice any issues!
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");
}About the :: syntax: http://spiderlang.org/#code-safety-global-scope-usage
About the extends/super syntax: http://spiderlang.org/#functions-inheritance
Maybe because I've written a decent amount of C++ I'm more acclimatized to the "::" syntax..