How To Dynamic Web Rendering?

Adam D. Ruppe destructionator at gmail.com
Fri May 13 08:19:51 PDT 2011


Jacob Carlborg wrote:
> How is it working out with a static type system, compared to a
> dynamic, for web development?

It's *much* better, especially for rapid development. The compiler
will tell me if my changes anywhere break things anywhere else,
so I can modify with confidence.

I can't tell you how many times I've made a minor mistake in PHP,
Ruby, or Visual Basic and had it slip through to production because
the code path was obscure enough to evade testing.

Sometimes, something similar does happen in D - to!int("") throws -
but, the compiler catches the majority of incompatible changes
instantly.

If I had int addUser() and change it to User addUser(), I don't
have to hunt every instance down myself. Just hit compile and
the compiler tells me where the change causes problems. (Rarer than
you might think - thanks to auto, a lot of the program is already
duck typed in a way. The actual return value name is rarely used.)


It also helps documentation to have good types. I often see stuff
like this in dynamic language docs:

function doSomething(options);

What does it return? What options are available? Maybe the text
will tell us that options is an associative array. UGH, I hate
that! Now, there's even less knowing what's going on.

D's documentation is a lot more helpful, and easier to keep up to
date.

string doSomething(Options options); // not much better yet....

struct Options;
int speed;
bool strictMode;
bool caseSensitive;


Ahhh, now I know!





Another thing that the static types enable that I don't think is
possible with dynamic functions is the automatic forms you see
on my link.

http://arsdnet.net/cgi-bin/apidemo/get-a-box

I didn't write any html for that. The library made it for me.

In the source, you can see it's prototype:
http://arsdnet.net/apidemo.d
	Element getABox(Color color);


The reflection was able to say "it needs a Color, and there's only
a handful of valid Colors - enum Color - so I can automatically
create a <select> box for this."

Dynamic types for return values can still do most the stuff my
api generator does. Whether it's a static function/template toHtml
or a dynamic property doesn't matter much.

But the parameters... I don't think it can be done without the
static types there.

(Another nice thing is the library checks the type too. Coming
off the request parameters, you have strings; dynamic types. But
going into the function, it knows it must be a Color, so it
checks. If not, an exception is thrown.

By the time you're inside the function, you can be guaranteed that
Color color is indeed a Color. Thus, to!string() to insert it into
the html attribute that I did here is perfectly safe. It's a
whitelist based filter, all done automatically.)



There are a few cases where dynamic types are helpful or needed.
D lets us opt in to them with only a minimal amount of fuss.

The places where I use it are:

1) Data from the user. Form variables are of type string coming
into the program. Once decoded, you have string[][string]. Your
program probably wants something else.

The to!() template in Phobos makes this pretty easy, or if you
want default value and get/post combined, my cgi class has a request
template:

int a = cgi.request!int("a");

That's similar to this in PHP:

$a = 0;
if(isset($_POST['a']))
  $a = (int) $_POST['a'];
else
if(isset($_GET['a']))
  $a = (int) $_GET['a'];


PHP is so outrageously verbose. And the PHP is buggy compared to
the D... if you do cgi.request!int("a", 10) and the user does a=txt,
the PHP result is wrong. It's not quite fair to compare a function
to a code collection though. A php function could do it right too.



Annnnyway, I'm digressing. Hell, I'm going on about weak types
instead of dynamic types! Even in Ruby, you'd have to do a to_i
since the url value simply is a string.



Back to dynamic types. The three other places where you see them
are databases and interfacing with external services.

2) Databases

With databases, you probably expect a certain type anyway. If the
column is typed as INTEGER, you probably don't want 'lol' in there.
But, the database takes care of that for you.


In my libs, I just use strings.

auto line = mysql.query("SELECT id FROM users WHERE id = 10").front;

res[0] == "10"


Conversions are now done the same as URL parameters:

int id = to!int(res[0]);


Oftentimes, I don't really care about it though; if I'm outputting
it to html, I'll just say:

table.appendRow(res["id"], res["name"])

and the like anyway. You want a string there, so it just works.
(appendRow is in fact a variadic template so it'd just work
regardless, but you get the idea anyway).


Thanks to static checks though, if I were to later change my mind
and wanted ints, or made the database return Variants or whatever,
no problem - the compiler will point out trouble spots to me.


Inserting data is the same:

mysql.query("INSERT INTO users (id) VALUES (?)", 10); // works
mysql.query("INSERT INTO users (id) VALUES (?)", cgi.post["id"]); // works too


Or using the data object class:

auto obj = new DataObject(mysql, "users");

obj.id = 10; // works
obj.id = "10"; // works just as well

obj.commitChanges();

(The DataObject can read too, offering database fields as obj.id
style properties. They always return string, just like plain query,
but are also read/write.)


DataObject can also be specialized automatically to use static
types if you like.

db.sql:
create table users(id integer primary key, name varchar(30));

file.d:

// parse out that create table to map the names and types automatically
alias DataObjectFromSqlCreateTable!(import("db.sql"), "users") User;

User a;

a.id = "12"; // type mismatch, fails to compile
a.name = "hello"; // works
a.nmae = "sad" // typo caught at compile time

a.commitChanges(); // otherwise it is still based on DataObject



In short, I have the best of both worlds, with the only extra effort
being writing to!() here and there and that one line to import the
sql definition.


3) HTML

I *want* strict typing when working with html in almost all cases.
It helps catch encoding bugs.

The one place where I want dynamics - fetching an element off
the html template - I have it, this time provided through classes.

auto table = cast(Table) document.getElementById("data-table");
assert(table !is null); // fails if it isn't a <table> tag

// use the table class's special functions


Forms, Links, and other types of nodes are handled similarly. The
Element base class though does most the simple operations. Being
plain old inheritance, the virtual functions act dynamically
enough.

Of course, if the HTML changes, that assert/enforce will trigger
at run time. We're still ahead of dynamic languages though: the
compiler will tell me what breaks if I remove the cast, with one
exception: I use an opDispatch there for attributes. That will
break some functions.

Table t = ...;

t.caption = "Hello!"; // changes the <caption> tag child

Element t = ...;

t.caption = "Hello!"; // sets a caption="" attribute


But meh, in this case, I like the flexibility of accessing
attributes like that. The compiler still catches more than it
doesn't - we're still ahead of the mistakes possible in dynamic
languages while keeping the convenience.


4) External services


This is where dynamic types are the most useful. Accessing Facebook,
Twitter, etc., returns xml or json with types that change based
on a lot of things. Is the user logged in? What url is it?

In this case, it's like the database, but the types tend to be more
complex. Simple string cowboying won't cut it.

Thankfully, D's Variant is up to the task.


Variant userRet = fbGraph(token, "/me");

// we know /me returns a json object from the docs, so fetch it:

auto user = userRet.get(Variant[string]);

auto name = user["name"].get!string;

// name is a string == "Adam D. Ruppe"


Not terribly hard. Robert Jacques IIRC has written an improved
std.json patch to make this work almost just like Javascript:

auto user = fbGraph(token, "/me");

user.name.get!string; // same as above


So D's definitely up to the job. The only difference is that final
use of get!string. I believe Phobos' to! works as well.



In the end, there's nothing web related in my experience that a
dynamic language can do that D can't do almost or just as well,
and plenty that D and it's static types can do that dynamic types
can't do, or require piles of painful tests and manually written
code or documentation to do.


D kicks the Web's ass. (And my web related libraries go even further
than seen here. My custom DOM offers a lot of things that are way
cool, enabling new CSS stuff, filling forms easily, in about 1/10
the code of doing it similarly in PHP, and without mucking up the
HTML. The web api/site generator makes D accessible through urls,
forms, javascript - view the source here for a glimpse of that
lib:
http://arsdnet.net/cgi-bin/apidemo/javascript

20 kb of javascript, including the auto generated API bindings!

And more stuff is packed in there too. Best of all: D, through
CGI, consistently does well or better than mod_php in my speed
benchmarks. I've barely tried to optimize too; there's a lot of
untapped potential.


If your host doesn't suck, dive into D on the web. You won't want
to go back.)


More information about the Digitalmars-d-learn mailing list