The syntax is inspired by Tcl!
The author really liked to write in Tcl (he says that it's the only language in which he can go back to a project after a year and continue working as if it was day 2 -- see, we're not even talking about Now itself and already concluded the author is stupid!), but was annoyed by some clunky constructions using multiple nested command execution, like when a command is used as argument to another command, especially noticeable when indexing lists or dicts.
So, instead of writing this:
set lista [list a "This value gets printed" c d] puts [lindex lista 1] # This value gets printed
In Now you could write this:
set lista [list a "This value gets printed" c d] print [o $lista : get 1] # This value gets printed
Yeah, but no. The syntax is actually crazy!
I know you're looking into the above example and thinking: "why?". Of course! Why try to improve a syntax that's awful from the beginning? Why keep building over such a terrible foundation?
Well, that's not even half of the problem. You could write that same code in yet another manner. The first line, for instance, could be written as that:
list a "This value gets printed" c d | as lista
Actually, there's even a preferred way of writing these "pipelines":
list a "This value gets printed" c d | as lista
The "pipe" (`|`) has a special meaning. Or not. It depends on how each "command" decides to interpret it.
You can understand it better by looking into how `print` works:
print "--> " [list 1 2 3] # --> (1 , 2 , 3) list 10 20 30 | print "--> " # --> (10 , 20 , 30)
You see? A pipe will basically make the result of the previous command to be used as the last argument for the next one.
And it gets worse
Getting an item from a list was done using `:`, that is like a pipe, but indicates that the next command is a method of the previous command's result. So, in this case:
print [o $lista : get 1]
You're basically telling Now to get the object "lista", call the method "get" with "1" as argument, then print the result of that.
But, as you already know, we could also write it as:
o $lista : get 1 | print
But what is that "o"???
I hear you. What is that `o`?
You see, in Now there's only one strict format for doing the most basic thing, that is calling commands, and that is:
command arguments?
So, this works fine:
And also this:
print lista
But not this:
$lista | print
Because `$lista` is not a command. It's simply a value.
So we need a command to reference a value. And this command is o. It takes some arguments and returns exactly these same arguments.
o $lista | print # (1 , 2 , 3 , 4 , "etc")
And there's yet another way to "get"...
print ($lista . 1)
You remember I just said there's "only one way" of doing things in Now? Well, it seems that rule is already broken!
Actually what happens is that the parentheses are a form of syntatic sugar: what they do is to turn an prefix notation into infix notation.
For instance, in this case:
print (1 + 2 + 3 + 4 + 5) # 15
What is actually happening is:
print [+ 1 2 3 4 5] # 15
The "language" sacrifices being coherent in the name of being easier to the developer. Preposterous!
Now, if you think about it, this construction:
o (a , b , c , d)
Is actually this:
o [, a b c d]
So it means the comma is actually an alias to `list`?
Yes, it is.
It focus too much on pipelines
Instead of mimicking the battle-tested behavior of good old languages, Now focuses on having powerful pipelines. The idea is to be able to do most of what you need without having to break the flow of the data from the first command to the last.
Again, preposterous
So stopping your train of thought to set a new variable is kinda considered an anti-pattern in Now.
A normal person would write code like this
# Remove the current user from /etc/passwd o $env : get "USER" | as username path "/etc/passwd" | as filepath o $filepath : read.lines | as lines o $lines | foreach line { if [o $line : contains $username] { skip } { print $line } }
But a seasoned Now programmer would write this, instead
scope "Remove the current user from /etc/passwd" { o $env : get "USER" | as username path "/etc/passwd" : read.lines | filter {o : contains $username : eq false} | {print} }
Explicit is better than implicit, amiright?
Did you noticed there's this weird `| {print}` in the end of the above program? That's an implicit foreach. And we all know that "explicit is better than implicit". Because it is.
But Now, instead of following this divine rule, tries to make the developer life easy by avoiding to write this all the time:
| foreach line { print line }
And you know what? There's even a implicit transform!
list 1 2 3 | {o : mul 10} # this thing | {print} # 10 # 20 # 30
But we won't bend to this sloppy way of thinking, of course we would write this much more correct, more explicit!, version:
list 1 2 3 | transform x { return ($x * 10) } | foreach x { print $x }
Ah, much better! Look how many characters we are typing, now.
Line-continuation is marked by a dot
Again, instead of doing things the way everybody does, that is, escaping the newline character using a \ in the end of one line, Now let the end of the line alone and indicates that the next line is, in fact, a continuation of the previous one.
So, this:
print alfa beta gama
Can also be written like this:
print . alfa beta gama
Or even:
print . alfa . beta . gama
Is this supposed to look like some sort of ASCII art???
What a joke!
You can handle errors inside the pipeline
We all love a good block of try/catch, right? But Now decided it's too normal for it to implement and, instead, have this thing called "events" that also serve to handle errors.
Like this:
http.get "http://example.com/teste" ! 500 {print "Maybe the server is down?" ; return error} ! 404 {print "Shit, this page doesn't even exist!" ; return error} ! * {print "Shit, some other error occurred..." ; return error} | return
It's not so catchy at first glance, but imagine you're doing it directly in your shell, like:
$ now :cmd 'http.get "https://example.com/teste" ! * {exit 1} | print'
It's not a multi-purpose programming language
If it's not supposed to solve every possible problem, how can it be any useful?
It's not even a programming language!
The author is emphatic in calling it a tool...
You don't write programs, you write documents
This may be the worst part.
Imagine that! Instead of writing a "script" or a "program", you are supposed to write a document! With a title, a description and... and... sections!
Just like this:
[Example Document] This document exemplifies some of the syntax of a Now document. [procedures/hello] parameters { who { type string } } print "Hello, $who!" [commands/run] parameters { who { type string default "world" } } hello $who
Like... you can't simply shove code into a file and call it a day. No, you have to follow the proper form, just like some ascient COBOL code.
And what about these 'commands'?
A Now document saved as `Nowfile` in the current directory will make running `now` without any arguments drop this in your terminal:
$ now Now Website passwd ---------> Test the code for 'grepping -v' the /etc/passwd file build ----------> Build the Website.
Now you see why Now forces you to write a title for your document...
In order to actually do something, you call one of the available commands, like `now build`.
It lives in a gray area between a shell and a real programming language
Now definitely is not something you could use as a shell, since you have to declare "system_commands" in order to call anything from the system it's running on.
[system_commands/ls] command { - ls }
Isn't that awful? Now even checks if the command actually is available before running your prog... document. It may be nice to not have any command not found being found during runtime, but if that's the price, I don't know, maybe it isn't worth paying.
It's written in D -- and nobody uses D
D is nice, but the language has no direction, no plans, right? You probably didn't even heard that before, since nobody talks about D.
Now has almost 8k LOC written in D. What a shameful decision that was!
It barely has standard library
Yeah, really. It has a whole lot of various commands, but nothing even close to Java or C#.
It has zero database connectivity baked in
In order to use a database, one have to rely on a "library". And libraries are not like shared-object libraries as normal people would expect: in Now, a library is implemented using a form of IPC: it keeps an external program running and send or receive calls to procedures using the standard input and output to send messages serialized in JSON.
So, technically, it's kinda easy to write a library to any DBMS, but who would do that?
It can't even work with YAML!
Yeah, it was abandoned because the author consider that there's no hope for YAML, that the format is terrible and overly complex. Now you have to convert everything to JSON if you want to work with data that's originally in YAML.
It implements weird concepts like "shells" and "commands"
Imagine your program have to call a bash script. Of course you're going to have it in a file somewhere in your project folder! But, no, in Now you can write this same script virtually like any other section in the document and call it a script, to be executed by some shell.
Like this:
[shells/bash/scripts/date] parameters { format { type string default "%Y-%m-%d" } } date +$format [commands/run] date "%Y" | collect : first | print "The current year is "
You can even define many shells that will call other programs and then write the "scripts" inside the document. Like, imagine having a document where you can write Markdown and it's capable of rendering itself.
And that's a waste. A folder with a 'document.md' and a 'run.sh' will have the same effect.
It's not Web-focused
What's the use on anything that can't serve HTTP???
Now is fully capable of serving SCGI, though, but what's the point? SCGI probably stands for SlowCGI, right?, the exact opposite of FastCGI! Who cares if it's simple? What we all need is fast!
Because every single Website we create absolutely must support 100k clients per second. We all know that.
And all that is only the tip of the iceberg...
You can even define many shells that will call other programs and then write the "scripts" inside the document. Like, imagine having a document where you can write Markdown and it's capable of rendering itself.
And that's a waste. A folder with a 'document.md' and a 'run.sh' will have the same effect.
It's not Web-focused
What's the use on anything that can't serve HTTP???
Now is fully capable of serving SCGI, though, but what's the point? SCGI probably stands for SlowCGI, right?, the exact opposite of FastCGI! Who cares if it's simple? What we all need is fast!
Because every single Website we create absolutely must support 100k clients per second. We all know that.
Stay away
My advice: stay away from the project repository on Github .