Wapp – a single-file web framework by the creator of SQLite
wapp.tcl.tk
wapp.tcl.tk
With regard to Wapp and some of the comments here disparaging Tcl...I've often said Tcl gets much more hate than it deserves. For a lot of tasks, it's fine. I wouldn't pick it for anything, but I understand why some folks still do. And, I did build my current companies first website with Tcl (OpenACS+AOLServer) more than a decade ago. It was more enjoyable to work with than all of the PHP CMS-based sites I've built for the company since then. I wouldn't rule it out, if there were some project I wanted to use that happened to be written in Tcl.
An informed rant about Perl might include these two function calls behaving differently and one almost certainly containing a bug, because function arguments are always a list:
some_function(@an_array, $a_scalar);
some_function2($a_scalar, @an_array);
Assume some_function receives @new_array and $new_scalar, and vice versa for some_function2. This trips up literally every new Perl developer (our UI guy, who is mostly a PHP and JS dev, ran into it just a few weeks ago).Lack of function signatures is another good complaint about Perl. It's still not realistic to use them in code that ships for old Perl versions (like for deployment on leading server distributions).
There are others, but, yeah. I also hate how simplistic criticism of Perl is these days. It's knee jerk and poorly-informed in most cases. That doesn't mean I'm recommending Perl for everyone, or that I'd pick it for every new project, just that I wish the dialog around it weren't so stupid so much of the time.
sub foo(@array,$scalar) { }
foo( 42, [1,2,3] ); # compile time error
Signatures are also first class citizens in Perl 6: check out https://docs.perl6.org/type/Signature for more information.I find it kind of funny primes are constantly used as a first filter on using Perl 6, despite it being one of the only languages with an efficient built in .is-prime method on integer types >;P I have a more contemporary version of Rakudo built locally too, so can see if this is something that's already gone away if you dont mind throwing your code in a gist/pastebin somewhere?
perl6 0m6.615s https://p.thorsen.pm/ab1769fe2778
This is Rakudo version 2017.10 built on MoarVM version 2017.10 implementing Perl 6.c. It's built with radkudobrew. Results are consistent across several platforms, I've also built on an iMac with OS X 10.1. This one is built on Ubuntu 16.04 x86-64.
FWIW, if I would just be interested in the prime numbers upto 1000, I would write that like this:
(1..1000).grep( *.is-prime )
Which for me executes within noise of your Perl 5 algorithm. For larger values on multi-CPU machines, I would write this as: (1..2500).hyper.grep( *.is-prime )
Around 2500 it becomes faster to `hyper` it, so the work gets automatically distributed over multiple CPU's.Am currently researching as to why your Perl 6 algorithm is so slow.
sieve_sundaram(1000)
instead of: sieve_sundaram(1e3)
then it all of a sudden becomes 4x as fast. In Perl 5 you never know what you're dealing with with regards to values. In Perl 6 if you tell it to use a floating point, it will infect all calculations to be in floating point afterwards. `1e3` is a floating point value. `1000` is an integer in Perl 6.Also, you seem to have a sub-optimal algorithm: the second `foreach` doesn't need to go from `1..$n`, but can go from `$i..$n` instead. This brings down the runtime of the Perl 5 version of the code to 89 msecs for me.
Since your program is not using BigInt in the Perl 5 version, it is basically using native integers. In Perl 6, all integer calculations are always BigInts, unless you mark them as native. If I adjust your Perl 6 version for this, the runtime goes down from 4671 msecs to 414 msecs for this version:
sub sieve_sundaram(int $n) {
my %a;
my int @s = 2;
my int $m = $n div 2 - 1;
for 1..$n -> int $i {
for $i..$n -> int $j {
my int $p = $i + $j + 2 * $i * $j;
if $p < $m {
%a{$p} = True;
}
}
}
for 1..$m -> int $k {
if ! %a{$k} {
my int $q = 2 * $k + 1;
@s.push($q);
}
}
return @s;
}
sieve_sundaram(1000);
So, about 11x faster than before. And just under 5x as slow as the Perl 5 version.I could further make this idiomatic Perl 6, but the most idiomatic version I've already mentioned: `(1..1000).grep( *.is-prime)`
Or on IRC: #perl6 on irc.freenode.org ?
Or the perl6-users mailing list?
So, I'm excited about it, too, but I can't use them until CentOS/RHEL 7 reaches end of life (and that's assuming CentOS/RHEL 8 gets a 5.20+ version of Perl, which isn't an entirely safe assumption). It's easy to blame CentOS/RHEL for this, because they ship an old-as-heck Perl version, but it's also reasonable to question why it took 20+ years for Perl to get function signatures in the core language.
The fact that it has managed to evolve into a decent, if poorly typed language, with some outstanding implementations, while maintaining 99% compatibility with "onmouseover" scripts from the 90s is a testament to its sound design.
Do you still run anything on Node.js 0.10? 0.10.36 was released in 2015, the same year as Perl 5.20. I doubt the mojority of modules still support it.
We target 5.10.1. When CentOS 6 is EOL, we will target 5.16, and so on. I don't like it, but I can't make Red Hat ship newer Perl versions. Software Collections has Perl 5.20, which is great for some folks, but it's not a good option for our projects, either.
It's worth noting that Python has the same problem on RHEL/CentOS. Maybe even more pronounced, because some system tools rely on Python, and it can even break them if you change your personal Python to something else (I use pyenv, and I have to remember to change my Python back to the system one when running Gnome Tweak Tool, and the like).
It is good to see mojolicious be mentioned here at HN.
Mojolicious::Lite docs http://mojolicious.org/perldoc/Mojolicious/Lite#SYNOPSIS
I have some ideas that I want to express in Tcl as well.
Flask [1] has similarities and IIRC the author of Flask, Armin Ronacher, has in the past proposed merging it with Bottle. However, the single file and dependencies thing is where the author of each framework disagrees.
Flask has tools that help with structuring larger apps and seems to be more widely used than Bottle.
Personally, I prefer bottle for things I know will remain small, just for the lack of dependencies and that I personally find the documentation easier to read.
It's not in Python, but I also really like the tiny Camping framework in Ruby. It's tiny enough and well documented enough that you can read and (more or less) understand the whole thing, even if you're not great at Ruby.
My path when learning web development kind of went from Camping to Sinatra to Rails, with periodic detours to Flask. The high level concepts are very similar.
CherryPy:
Mako:
It's quite easy to pick-up and does the job very well. It supports running directly over http, but you can also run it in wsgi or fastcgi modes without issues.
And it's also quite stable in term of APIs, my projects are now 4 years old, and I didn't have any breaking changes in their API. It makes it quite easy to support various distributions and version without kludges in the code to handle different versions or having to bundle cherrypy with the application. Even my monkey patches of the framework (slight change in the configuration parser) are not breaking ^^.
First app is a web config interface on a Raspberry Pi-based IoT device. Web config app will be almost identical server-side so as to allow config from anywhere. I was going to do it all in CGI but this is much improved.
However, it should be noted that TCL is famous for being a language that can be described in 12 rules:
And the tutorial is really good:
https://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html
Obviously, there's a lot more online reference material and a bigger community for Python, but if you are interested in learning TCL, don't be afraid to go for it.
It's a framework that allows you to start with a single file, but also allows you to more logically then split your application up and grow with a huge amount of plug-ability while providing many sane defaults to start off with.
It is not a batteries included framework, so it gives you the flexibility to figure out what is best for your application vs being forced into a certain convention.
Full disclosure: I am a maintainer for the Pylons Project with a focus on: Pyramid, WebOb and waitress.
(To me, that's a plus)
Back before serverless, we called it shared hosting.
Of course, fork() is not especially fast, so people came up with Fastcgi: persist the process and let it handle multiple requests. Then people started writing java where the startup time was prohibitive, and "application servers" like Tomcat came into being.
fork itself is pretty fast, relatively speaking (unless you have a large virtual address space and 4K pages or similar). fork+execve+process-runtime-initialization is much slower.
On my X201 (anno 2010), with 10000 iterations, sequential fork+exit(0)-in-child+wait takes:
$ /usr/bin/time ./forkfest
2,49 real 0,38 user 2,19 sys
while sequential fork+execve("/usr/bin/true",...)-in-child+wait takes: $ /usr/bin/time ./forkfest2
10,99 real 3,10 user 7,94 sys
EDIT: also, My X201 is clocked at 1199 MHz (50%) for power saving reasonsFastCGI is a classic example of second-system syndrome. I once looked at the spec. It was ridiculously overdesigned. SCGI (Simple CGI) solves the same problem (reusing a server process for multiple requests), but its spec literally fits on two pages: http://www.python.ca/scgi/protocol.txt - It's also supported by nginx by default. (Don't know about Apache etc.)
You're right, but Windows was different. In Windows/Asp.Net land (which was a good chunk of shared hosting in the early 2000s), Shared Hosting providers were using AppDomains to isolate sites. IIRC, AppDomains were isolated by the .Net runtime rather than more robust process isolation.
CGI was abandoned because of the slowness of process forking, but with modern kernels, new compiled languages, and better reverse proxy servers, I believe that the speed difference is trivial in regards to the advantages:
- Deployment can be done by simple file upload.
- Process isolation adds security and reliability.
- CGI scripts/binaries are vendor agnostic and can be run/tested locally
- CGI scripts can use any language, are stateless, promote hyper modular design (aka functions) and are generally minimalistic in nature.
[1] https://bigcgi.com/ [2] https://github.com/bmsauer/bigcgi
Are you thinking something like "FastCGI, except over stdin/out instead of a listening socket"? Since that sounds like it could work pretty efficiently if (unlike nginx's fcgi implementation) it supported multiplexing.
I like the idea of communication via stdin/stdout though, I'll add that to my notes.
I actually was going to remove that from the roadmap entirely, because lately I really like the process isolation and statelessness of regular CGI.
Thanks for your comment!
Shared state and locks are evil.
https://en.wikipedia.org/wiki/2017_block_of_Wikipedia_in_Tur...
But actually, Lambda can keep your server open to serve multiple requests without spawning new processes all the time.
I realized that the key feature is not having the server open all the time, only when necessary. So I took systemd's socket activation idea and added socket deactivation, i.e. sending SIGTERM to the server after a period of inactivity: https://github.com/myfreeweb/soad
Plus, one of the things that really deserves more hype and popularity is CloudABI https://nuxi.nl an ABI that lets you have one binary that runs on multiple operating systems as is and always runs sandboxed.
The serverless runtime of my dreams just takes CloudABI binaries (packed with files in a tarball) that listen for HTTP on a given socket, and does the activation-deactivation thing to only run on demand :)
In that regard, it's closer to FastCGI than CGI itself.
We had a C application server and used TCL as a business logic language. It was a great fit for writing code fast and ease of maintenance.
You can hear me get a laugh when I say we use TCL in a talk I did here:
Worse yet, a lot of the tools aren't open source or freely available, even for tinkering. I'll happily pay for a license if I end up using it for business, but I'm not going to pay hundreds of dollars up front just to play around with a niche language.
There's lots of great languages out there which include completely free and open source tools. Maybe I'm spoiled.
I can't think of how Tcl/Tk docs can be massively outdated given that Tcl/Tk maintains almost 100% backwards compatibility, so most of the old advice works just as is.
Regarding open source, nearly all tools are not only open source, but usually under very permissive licenses (e.g. Expat or BSD-2), and there are in fact very few commercial closed-source tools (basically Komodo, what else?).
Are you sure you actually tried Tcl/Tk and not something else?
As an aside, Tcl was influential as a source of inspiration in the early days, ranging from event-driven programming, to web servers big (AOLserver) and small (Brent Welch and Stephen Uhler's <200 line server/HTML parser) back when "normal" was forked CGI scripts.
Come on guys, let some technologies dies peacefully, Ok? We don't want those days back :)
There are very good reasons that stringly typed programming is frowned upon and 'performance' is very seldom one of them.
There's also seems to be a weird assumption that everthing-is-a-string means that you don't have to think about types. It's actually the exact opposite since now you don't have types for the compiler/runtime to help you to combine values in well-defined ways.
(I realize that the thing was written ages ago and we/the author may have learned a thing or two in the mean time.)
Seriously, am I somehow supposed to divine your criticism of my post from that link?
This is a problem with weakly typed languages in general, but stringly typed is the nadir of weakly typed.
The problem increases geometrically with the size of the software system - you can't make building blocks to build other software on because the foundations are too unstable, so the only thing that really works is short programs that don't do very much - or, as some people put it, "toys".
He mentions strict format checks as a way to offset that, but I don't think that's nearly enough.
Binary "wapptclsh" + your .tcl script + optionally .sqlite file, just 2-3 files are sufficient to make an app chroot/jail/container, if I understood correctly section 2.0 here: https://wapp.tcl.tk/index.html/doc/trunk/docs/compiling.md
For example, I always feel that Tcl is better than Python for GDB scripting. At least, I really don't like typing parentheses in an interactive console. Also, there is no 'real' (read: general purpose) programming language that is able to beat BASH in terms of ergonomics, even though we all know BASH sucks when the program is getting large.
One of my heterodox opinions is that "shell" is actually two languages, an interactive language for moving around the system and executing commands, and a non-interactive language for programming system interactions, and they really shouldn't be the same thing because there's a list of things as long as my arm that should be one way for one case and the other way for the other. "Error handling", for instance, is an entire category on its own; what a human sitting at a shell wants and what a program wants are just night and day different, and at least one side is going to lose if you try to straddle the gap with one language.
HTML is not a serialization of code objects. It is a document authoring format. The DOM is just a way of modeling the documents so that code can perform various transforms on them. But the document is the important part, not the model.
And while the language had its warts, the syntax was relatively easy to comprehend, so even if things went southwards, it didn't take long to see where you made your mistakes. As long as you didn't upvar and uplevel the heck out of it.
Also very easy to create DSLs with it and drop down to C if you needed a function to be a bit faster.
Tcl would be a lot more popular if it weren't for Sun's divided interests, and if they managed to get something CPAN/GEM/NPM-ish up waaaaaay earlier.
Source: https://git-scm.com/docs/gitk
Actual tcl source: https://github.com/git/git/blob/master/gitk-git/gitk
http://hitchdev.com/strictyaml
Ideally there should only be one scalar type (strings), two ways to represent strings (simple | multiline), just one way to represent mappings and lists. No nodes/anchors, no "YAML is a superset of JSON" silliness and absolutely no implicitly typed scalar values.
Thank you!
I always found interesting how the Tcl community solve things, using simple and powerful Tcl metaprogramming features (see beautiful examples on wiki.tcl.tk).
I've done a couple of small business solutions in Tcl/Tk as desktop applications. Now I feel more encouraged to try to develop new ones for the web :-)
The README.md file is the homepage. It is intended to be displayed using the URL https://wapp.tcl.tk/index.html/doc/trunk/README.md and the hyperlinks are relative to that URL. When you click on the File menu, it shows the README.md file using a different URL - http://wapp.tcl.tk/index.html/dir?ci=tip - and the hyperlinks don't work for that URL.
Perhaps the right solution is to rename the README.md file to something different so that it is not displayed by default from the Files menu...
But I have yet to see a beautiful TCL application. Web apps today can't just work, they have to be user-friendly and familiar to a wide audience. Would love to be proven wrong, but TCL does not seem to fit the bill.
I'm not necessarily advocating for that... but what on earth does anyone's choice of server-side framework have to do with the "user-friendliness" or "familiarity" of the client-side UX?
You can serve up a bleeding edge Vue.js app from a PHP backend, or you could serve up a bowl of jQuery spaghetti from Rust or whatever new language comes out next week. These matters can sometimes be tangentially related, but are largely orthogonal.
You SEEM to be referencing the "Tk" portion of Tcl/Tk. Tk is the desktop GUI framework that comes with most distributions of Tcl. But it has no apparent relevance to this or any other Tcl-based web framework.
This is kinda like dismissing a Java server-side web framework because Swing is ugly, or dismissing C# on the web because you don't like WPF.