
Rosencrantz – A Web DSL for Nim - Varriount
https://github.com/andreaferretti/rosencrantz
======
keyle
Nim is one of those underpublicized language. It's really good, I will leave
it at that. I've used it a few times and it takes maybe 10 minutes to get back
into it. It's perfect for making tools.

~~~
Gonzih
Yeah, I also had positive experience with nim. I'm not sure why it's so
unknown, maybe because it fits in the same niche between rust and go and not
backed up by any major company in industry. But I highly recommend trying Nim
out!

~~~
3pt14159
Nim is great, and I use it (in production), but I know exactly why it isn't as
popular: Nim is fucking huge.

Most programmers I know don't even know what a pragma is; Nim uses them
extensively. Nim has types, objects, is low level, can be compiled to shared
objects (something that didn't come out to Go until 1.5), macros, generics,
templates, oh and it compiles to both C and JavaScript (and C++, and Objective
C in case you need easy bindings for those), dynamic dispatch, mutually
recursive types, pointers, named arguments, tricky hash tables, procedures
that look like functions or methods (whichever suits you), and an irrelevant
casing (spellLikeThis is the same is spell_like_this - case only matters for
the first letter and underscores don't matter), and many more.

All of this on top of a hyper fast (~2x the speed of Go) compiled language.

Most other very complete languages are not compiled so you can kinda muck
around in a repl and use introspection to figure out whats going on. Nim isn't
like that. You need to think and figure things out when you're first learning
it. Furthermore Nim isn't yet at 1.0 and lacks its killer library. Go and Rust
are easier to get started with because they are simpler languages. They are
easier to teach and easier to write documentation for.

Nim kinda reminds me of Ember or Rails or C++(see note): Huge, but worthwhile
to learn because you'll never feel constrained by it. I highly doubt it will
ever be as mainstream as Go though. I've generally found that most people are
too lazy to learn harder languages / libraries.

Note: I do not like C++ for many reasons. The tooling is crufty, syntax is
awful, impossible to reason about a codebase unless its picked a subset of
C++; but the one thing I'll grant C++ is that _you can always eventually get
what you want done_.

~~~
nickpsecurity
What you've just described is a hodgepodge of stuff thrown together. That's a
_lack_ of language design with a surplus of features. My readings on older
reports for language designs showed the art was figuring out just how much
power to include in the language & keeping it all consistent/sensible. One can
overdo it.

An example of a clean, carefully-thought language that's low-level,
consistent, and very powerful is PreScheme:

[https://en.wikipedia.org/wiki/PreScheme](https://en.wikipedia.org/wiki/PreScheme)

Modula-3, a C++ and Java competitor, was another where they made careful
tradeoffs of features, safety, compile speed, run speed, and ease of
learning/reading.

[https://en.wikipedia.org/wiki/Modula-3](https://en.wikipedia.org/wiki/Modula-3)

There's also some dialects of Haskell and ML focusing on system level. Didn't
hit those levels of maturity though. What I'd like to see is someone take the
Nim tech, subset it, change inconsistent stuff to be consistent... basically
clean it up into a coherent picture... then deploy that as a new language. It
could be pretty awesome if it happens. Right now, it's too complex and
incoherent except for people, as you said, willing to do a huge learning
curve.

Note: Nim is so huge now that it might be easier to add Ada static checks and
Rust dynamic/concurrency checks to PreScheme instead of fixing Nim. You'd have
a low-level, safe LISP. Put a 3GL front end on top of it for more adoption.
That's what Julia people did.

~~~
3pt14159
Well I don't have a negative view of Nim in general, and I wouldn't describe
it as a hodgepodge. I would describe Nim as a language that doesn't hold you
back and doesn't save you from yourself. Personally I refrain from using most
of the complex stuff, but when I need it I love how it is there for me. For
example, the shared objects make it very easy for me to just roll things in
Nim then link them to Ruby through the FFI.

Will your average developer need these features? No. But the average developer
writes ASP, PHP, or JavaScript. I'd rather be formidable even if it means
doing the work.

~~~
nickpsecurity
"and I wouldn't describe it as a hodgepodge. I would describe Nim as a
language that doesn't hold you back and doesn't save you from yourself."

That's kind of vague. When I say hodgepodge, I mean they threw in all kinds of
capabilities into the language without integrating them into a consistent
whole. The examples I gave leave no surprises. What you see reading others'
code is even expected. You could do about anything in a variant of PreScheme
that you could do in Nim given almost any language feature gets ported to a
LISP as a library. Except, it's all consistent in its style, syntax, and
techniques for doing whatever it does. Nim seems to lack that very-significant
property that affects uptake, ease of formal analysis, and maintenance burden.

So, the language is powerful. People are doing neat things with it. Just lacks
design traits that have historically been important for programming languages
in terms of getting and keeping developers/users.

------
dom96
Slightly off-topic but related to Nim. Having been inspired by the Rust
community survey we have just created a similar one for Nim. I would
appreciate any and all answers, especially if you've never used Nim before!

[http://goo.gl/forms/XJ3TPsaiIQe5HlTB2](http://goo.gl/forms/XJ3TPsaiIQe5HlTB2)

------
k__
Sad to see all these [] and () in Nim, which has such a beautiful syntax to
start with.

~~~
pathsjs
What would you suggest instead? Routes are naturally nested, and overloading
[] seemed the best choice

~~~
Nycto
I came here to say the same thing as the GP. So while I am not the poster you
responded to, I'll pitch in my opinion.

I've written a number of Nim libs at this point. Rosencrantz is missing the
idiomatic 'feel' of Nim -- blocks and trees. I would rather see a syntax like
this:

    
    
        let handler = firstOf:
          get:
            firstOf:
              path("/api/status"):
                ok(getStatus())
              pathChunk("/api/message"):
                accept("application/json"):
                  intSegment(id):
                      let message = getMessageById(id)
                      ok(message)
          post:
            path("/api/new-message"):
              jsonBody(msg):
                let
                  id = generateId()
                  saved = saveMessage(id, msg)
                if saved: ok(id)
                else: complete(Http500, "save failed")
    
    

I believe all of that should be possible using templates; grab the AST for the
`stmt` passed to each function, then iterate over each node.

~~~
pathsjs
The problem with this approach is that it would be difficult to make handlers
first-class. What if your post routes are a handler imported from another
module?

Templates would allow for the syntax you present, but do not combine.

~~~
Nycto
That's not at all the case. Templates can return values. So really, you could
think of the templates as syntactic sugar around the existing functions you've
got right now.

For example, the 'firstOf' template above would be responsible for scanning
the AST it's given, taking each node and putting it in to a sequence. Then it
instantiates a Handler with that sequence and returns it.

~~~
pathsjs
Of course template can return values.

The problem is that they need to be given the AST. What if one constructs a
handler somewhere in another module (say an authentication handler) and you
import it? How can you reuse it, considering that it needs to surround other
handlers (that is, if auth fails, you do not go inside inner handlers)?

With Rosencrantz it is easy: if `auth` is our authentication handler, and in
your module you define a handler `h`, you can use `auth -> h`, or `auth[h]` if
you want to spell `h` inline.

Now, what you could in fact do is write a template `authTemplate` that takes a
handler `h` and returns `auth -> h`, so that you can still write in template
style. But you have to do this for all handlers.

It could make sense to provide such templates for builtin handlers, though...
want to chime in? :-)

------
egeozcan
Why not Jester[1]? Jester has a better API, IMO.

[1]: [https://github.com/dom96/jester](https://github.com/dom96/jester)

~~~
pathsjs
I wrote Rosencrantz because I do not like the Jester API very much.

Jester, like many other frameworks, hardcodes exactly what to do with a
Request - say parsing the headers, parsing the form if the content type
suggests so, always return a date, and so on.

This is not bad per se, but I prefer to have something I can compose. Say, I
have a working route `r`. If I want to add CORS support, for instance, I can
just make a handler `h` that adds CORS headers and then use the route `h ->
r`.

This is more flexible and leaves fine grained control over which headers to
require, or return, how to do content negotiation, and so on. You can separate
your routes for `POST` from those for `GET` in different modules and then
combine them, or maybe separate your authentication routes from the business
logic ones. You can easily create handlers that work as middleware, and so on.

In short, the thing I like about this approach is that handlers become first
class objects that you can manipulate and create freely

~~~
egeozcan
I see. So, hopefully not being too shallow, this is like Jester with
middleware support. I'll give it a try.

------
Cyph0n
This is inspired by Spray, which I just learned about recently. The project is
being migrated to Akka, so it's going to have support for the foreseeable
future.

It looks like a great fit for Nim though.

------
vittore
Now I am waiting for a web server Guildenstern in Nim.

