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.)