
Crow – C++ Microframework for Web, inspired by Python Flask - jeremyjh
https://github.com/ipkn/crow
======
ipkn
I'm writer of this project and it's not completed yet. I planned to publish
this after finishing basic features and documentations.

~~~
jvickers
It looks very convenient for making some relatively simple web services (based
on me not knowing much C++, others would get more mileage probably). It looks
like the kind of C++ project of a moderately small size that's implementing
something that I'm very familiar with already, so I think it will be useful to
help me learn C++.

I have a couple of questions, and that is what is the reason for only having
.h files with no .cpp files in the main part of the microframework? Did
something force you to do it that way or was it done like that because you
like that code structure?

~~~
Mr_P
Header-only libraries have several advantages (see
[http://en.wikipedia.org/wiki/Header-
only](http://en.wikipedia.org/wiki/Header-only)). Most-notably, they are dead-
simple to include with a project, as opposed to having to separately build and
link to a shared-library.

~~~
frankzinger
Yeah but usually "header-only" implies templates, of which there seems to be
little in this case. Without templates there's little point in putting
everything in headers because all the code becomes inline.

Inlining everything is bad because:

    
    
      - it makes the binary much bigger.
      - the smallest code change forces library users (applications) to be recompiled.
    

For libraries it's usually better to go to the other extreme: hide as much
code and data as possible in the source files. See, for example,
[https://en.wikipedia.org/wiki/Opaque_pointer](https://en.wikipedia.org/wiki/Opaque_pointer).
It greatly reduces the need for applications to be recompiled when the library
is updated.

It's actually very unusual to put all function implementations inline (edit:
as in, inside the class declaration) in C++. I wonder whether the author is a
heavy Java user.

~~~
geon
> because all the code becomes inline.

The language says that's just a suggestion to the compiler, right? Does any
compiler actually inline for non-trivial methods?

~~~
pbsd
`inline` has a different meaning in C++. The compiler is free to inline the
call if it wishes to, but `inline` means that the same function can be defined
in multiple translation units without breaking the one definition rule.
Example:

    
    
        // header.hpp
        inline int f(int x) { return x + 1; }
    
        // a.cpp
        #include "header.hpp"
    
        // b.cpp
        #include "header.hpp"
    

If f was not marked inline, linking a.cpp and b.cpp together would find a
conflicting method f, and compilation would fail. `inline` lets the compiler
ignore this, and it simply picks one of the multiple definitions as the 'real'
one and moves on with the compilation.

~~~
mtdewcmu
What you are describing sounds a lot like 'static' in C, which marks a
function to not export its name, so it can't be seen from outside the file.

'inline' in C is a hint to the compiler that you'd like the function inlined.

You can combine the two, and, in fact, it seems like a good idea IME to also
use static if you're using inline.

Are you sure c++ is that different?

~~~
pbsd
`static` will result in a copy of f for every translation unit (without LTO,
at least). `inline` will not. `static inline` is effectively the same as
`static`, with a slight hint to the compiler to inline the call.

`inline` is used extensively in C++ to make header-only libraries possible;
otherwise you'd get constant symbol clashes during linking. With `static` you
would get enormous size blowup. It has little to do with the actual inlining
of the call, which is mostly up to the compiler.

In C, the situation is complicated. `inline` does not exist in C89. GCC has an
interpretation of it for C89 (-std=gnu89), which differs from the C99
interpretation. The only safe way to use inline in C is usually to couple it
with `static`, unless you know what you're doing. The C99 interpretation of
inline is similar to C++, but once again not exactly. For example:

    
    
        // header.h
        // int f(int x);
        inline int f(int x) { return x + 1; }
        // a.h
        int a(int x);
        // a.c
        #include "header.h"
        #include "a.h"
        int a(int x) { return f(x); }
    
        // b.h
        int b(int x);
        // b.c
        #include "header.h"
        #include "b.h"
        int b(int x) { return f(x); }
    
        // main.c
        #include "a.h"
        #include "b.h"
        int main(int argc, char **argv) {
          return a(argc) + b(argc);
        }
    

This is code that compiles perfectly fine in C++, but is invalid C, because
when the compiler decides not to inline the calls to f, it has no linkage of
its own. But when one declares f to have linkage (by uncommenting that line in
header.h), we now get 'multiple definition' errors.

~~~
mtdewcmu
Thanks for that. I always hoped that static C functions would not be generated
if they are never called, at least. Which I can't see anything to prevent.

It sounds like you've confirmed my intuition about inline in C, and I find
inline to be only marginally-useful at best. inline functions are
syntactically-prettier than macros, but they lose the other major benefit of
macros, which is increased flexibility about typing and being able to interact
with syntax in ways that functions can't. I get the impression that inline
probably didn't need to be included in the standard, or, at least, somehow
they blew the opportunity to add something more useful.

C's situation still seems less complicated than C++'s. I can't grasp exactly
what C++ 'inline' actually tells the compiler to do, based on your
description. It sounds like 'inline' in C++ is just a smarter 'static'. Why
can't those smarts be implanted into 'static'?

~~~
pbsd
`inline` indicates to the compiler: "this function has external linkage, and
no matter how many times it's defined it is to be defined only once in the
final linked output". It's the same as if there was no inline, but when the
linker finds multiple definitions of the same function it is allowed to ignore
them instead of failing. It also serves as a inlining hint to the compiler in
its free time.

Note that you don't necessarily have to type `inline` to have inline
functions. Methods defined in the declaration of a class are implicitly
inline; so are template functions (but not explicit specializations).

The reason it's called `inline` instead of something else probably has
something to do with the committee's aversion to new keywords, and commitment
to backwards compatibility. Changing `static` would probably break a lot of
code: think what would happen to static variables inside static functions.

~~~
mtdewcmu
'static' is old. It must have meant something to Kernighan and Ritchie.

I see no connection to the word inline in the C++ meaning. In C, at least,
inline means inline.

My guess is that the C++ inline got its meaning from the winding path of c++
history, and only makes sense in the context of that history.

~~~
geon
I guess it is that in C++, methods implemented in the class declaration are
implicitly "inline". It could be done to avoid the problem outlined above.

------
mike-cardwell
The way your routes work mean that a response is expected to be immediately
generated and returned. It would be much nicer if a response object was passed
to the callback and you could return immediately from the callback, but send a
response independently, when you are ready. Kind of like this:

    
    
      CROW_ROUTE(app, "/about")
        ([](Response res){
            res.send("About Crow example");
        });
    

Why you might ask? So you can do this:

    
    
      CROW_ROUTE(app, "/about")
        ([](Response res){
            responses.push_back(res);
        });
    

And then some independent method could come along and do the res.send() when
it is ready. The connection would hang until res.send() or similar is called
on it. There would also be methods on the Response object so you can see if
the connection is still alive etc, and maybe the ability to set timeouts
directly on the Response object.

[edit] This would allow people using your framework to implement long polling
without locking up an io_service thread for each connection. It would also
make it easier to add support for web sockets etc at a later date.

[edit2] This is how NodeJS works. Both a request and a response object is
passed to the callback, then you can do for example:

    
    
      function callback (req, res) {
          setTimeout(function(){
              res.writeHead(200, {'Content-Type': 'text/plain'});
              res.end('Hello World\n');
          }, 5000);
      }

~~~
ipkn
I agree that allowing implementing long polling with crow is important, just I
didn't know a good way to do that. Your suggestion is big help.

I think supporting both way is better if there is a enough explanation. I
don't want to drop a simpler way to do the same job.

    
    
      CROW_ROUTE(app, "/about")
        ([](){
            return "About Crow example";
        });
    
      CROW_ROUTE(app, "/about")
        ([](Response res){
            res.send("About Crow example");
        });

~~~
shanemhansen
^this is exactly how twisted implements their web resources.

------
ivoras
I don't code much in C++ but recently I started a project just for fun and
found it much easier to make a FastCGI app than I anticipated. Yes, there are
still some exceedingly low-level stuff to write by yourself, but overall, it's
just fine.

For example, this is how I handle routing:
[http://goo.gl/G3jvGp](http://goo.gl/G3jvGp)

A simple static map of regexes and pointers to methods will do the task
nicely, and the principle is extendible if I need to create or compose complex
apps.

There are still things which I would need to encapsulate to make it a rapid
development framework (such as QUERY_STRING handling in
[http://goo.gl/l7Ff75](http://goo.gl/l7Ff75)) but it's surprisingly non-
painful.

------
rch
I always wanted to give okws (the c++ server that ran/runs okcupid) a try
sometime. It seemed like a great design, if a little tough to get going,
because of some dependencies. The license made it a tough sell at the company
I was with when it came out too.

------
mappu
Today i learned constexpr, enum class, and operator "". Thank you.

The full trie implementation caught my eye, are there no suitable alternatives
in std or boost?

Mixed tabs and spaces (?) cause strange display in github in json.h from 555
through 670 or so.

Also at the start of json.h it seems a shame to repeat __builtin_expect rules,
how about #if defined() || ?

~~~
sdab
huh, never seen operator "". Seems to be a c++11 feature.

[1] helped me understand it a bit, but Im not sure I see a compelling use
case. Does it just provide a shorthand for calling functions on primitive
types (and strings) or have I misunderstood? While requiring less characters
might it not decrease readability?

1\.
[http://en.cppreference.com/w/cpp/language/user_literal](http://en.cppreference.com/w/cpp/language/user_literal)

------
innover
I like the technique to generate compile error when there is a mismatch
between format string and actual argument list and type - This is what only
statically typed language can do and dynamically typed languages like python
can't do.

Maybe this technique could be applied in printf or other C++ APIs using format
string.

~~~
unwind
Not sure if you're being ironic, but you're describing e.g. GCC's "format"
function attribute ([https://gcc.gnu.org/onlinedocs/gcc/Function-
Attributes.html#...](https://gcc.gnu.org/onlinedocs/gcc/Function-
Attributes.html#index-g_t_0040code_007bformat_007d-function-attribute-2889)),
it makes the compiler verify the arguments for printf() and other format-
string functions.

It's not new, it has been in GCC for quite a number of years (not sure how to
check this quickly).

 _UPDATE_ : I found a list ([https://ohse.de/uwe/articles/gcc-
attributes.html#func-format](https://ohse.de/uwe/articles/gcc-
attributes.html#func-format)) that says format was added in GCC 2.3-3.4
(whatever the range means). GCC 3.4.0 was released on April 18 2004. Now I'm
sad I didn't say "ten years" above, as my original hunch was. :)

~~~
nly
Specific to printf and scanf format codes though, not under the control of the
programmer.

------
boatzart
The way the crow::black_magic::get_parameter_tag works is very impressive. I
don't think I ever would have thought to do this with a recursive constexpr
like that. I'm a huge fan of providing compiler errors whenever possible, so
I'm glad to be able to add this trick to my toolbox.

------
przemoc
C++ _micro_framework using boost. Just couldn't resist to notice that. ;) (I
know that boost consists of many libraries, many of them are header only, etc.
so using them doesn't necessarily result in terrible bloat.)

Will have a proper look at it later.

~~~
ascotan
I noticed that to. For C++03 you might need it for scoped_ptr/shared_ptr, but
not if you're going to require C++11. If you're going down the -lpthread route
you should probably just use them rather than forcing the include on boost
threads.

------
Sir_Cmpwn
Is this inviting remote code execution exploits on your websites? One of the
reasons most people don't write C/C++ for websites is safety. It's a lot
harder to introduce entire categories of bugs when you use safer languages.

------
neuromancer2701
It would be interesting to see how this would work with Cheerp(former duetto).
Building a frame work on top of that project has been an idea I have been
contemplating.

------
has_bin
Much better!

------
daftshady
It looks like very interesting project

------
WoodenChair
This is going to sound overly critical and judgmental to many - but to me, I
just don't understand how you can spend the time involved in developing an
entire web framework, and don't have the time to write a couple paragraphs for
a README on how to use it and what it's all about along with some examples.
I'm not talking full documentation - I'm just talking a few sentences and an
example or two. Why bother releasing it before then? Why let people
unnecessarily struggle to use it? Maybe somebody posted it here before the
author was ready (assuming they're different people).

~~~
adamnemecek
See example.cpp. Also the codebase is very small so not much documentation is
necessary. Also I'm pretty sure it's more of an exercise than a framework
that's intended to be actually used.

~~~
has_bin
And that line you wrote would be a perfect example of what to write.

I agree, I find this annoying.

