Coding

A Decade Plus Later and HTML/CSS is Still Schizophrenic Crapware

After more than a decade of web development, I'm of the firm belief that HTML and CSS are fundamentally flawed dog shit and in desperate need of a ground-up replacement. And no, HTML5 does nothing to change my mind.

There are many, many reasons for this and I won't attempt to build a full case right now, but here's the latest bit of HTML "fun" I've hit:

html-is-shit.html:

<!DOCTYPE html> <html> <body> <div style="width: 90%"> <table> <tr> <td>Short</td> <td> A little bit of text. Mobile browsers use small font. </td> </tr> <tr> <td>Long</td> <td> Lots of text. Mobile browsers use big font. Lots of text. Mobile browsers use big font. Lots of text. Mobile browsers use big font. Lots of text. Mobile browsers use big font. Lots of text. Mobile browsers use big font. Lots of text. Mobile browsers use big font. </td> </tr> </table> </div> </body> </html>

Notice there is nothing to change font sizes. And yet, when viewed in various popular mobile browsers (such as the Android versions of Firefox and Chrome) not only is the basic font size absurdly small - much smaller than the browser's normal default, but ONE of the cells uses a completely different font size than the rest!:


(click to enlarge)

And no, setting [-whatever]-text-size-adjust: 100% doesn't fix this issue, nor does explicitly setting all font sizes to 1em.

Safari on iPhone, as is typical for Apple, also has it's own...uhh, "creative" interpretation of basic sense: The different columns use different font sizes.

Seriously, what the fuck?! And people actually want to write their applications in HTML?

Read more


Fanning the Code Convention Flames: Parens After Keywords

Much like the famed spaces vs tabs, there are differing preferences about whether to put a space between a keyword and any following parenthesis:

if(condition)... //vs if (condition)...

I submit that including the space is a stupid convention unless you also handle functions the same way:

void foo (int a) {} foo (4);

Which, of course, is rarely ever done, even in codebases that always put spaces after keywords like if.

Read more


Downloading Files From Plain Batch - With Zero Dependencies

Background

I've been mulling over some ideas on a bootstrapper for D. I'd like users and contributors, on either Windows or Unixy systems, to be able to go from nothing to anything they need as easily as possible.

In a best case scenario, these would be the ideal qualities:

  • No prerequisites, other than what's likely to be already installed on nearly any system.
  • One-step setup: No "download this archive, extract it somewhere, and run the file named blahblahblah".
  • No prebuilt binaries for the custom tools: Because then that would need to be bootstrapped, too. Not a big problem on Windows, but prebuilt binaries in the Unix words can be tricky due to all the varieties (not impossible of course, but non-trivial).
  • Scriptable
  • As little shell/batch scripting as possible: Get straight to a bootstrapped compiler so everything else can be written directly in D.
  • Maximum compatibility

Those are lofty, conflicting, and perhaps unrealistic goals, but I'd like to get as close to that ideal as possible.

One interesting sub-problem of this is how to handle Windows:

Due to the first two goals, it's clear some way will probably be needed to automate downloading files from the internet. On Unixy systems this is easy - most already have either wget or curl installed (and the ones that don't are generally very expert-oriented anyway, so it's not too terrible to expect those users to install wget or curl themselves).

But Windows has no built-in command-line tool to download files. You can get curl and wget for Windows, but most Windows developers won't already have them installed. So what to do on Windows? It's not like we can just wget a copy of wget itself...

Step One: Download Tool in VBScript

We can't download files on just any run-of-the-mill Windows box using batch scripting. But we can do it using VBScript, which is a standard part of Windows:

'File: download.vbs Option Explicit Dim args, http, fileSystem, adoStream, url, target, status Set args = Wscript.Arguments Set http = CreateObject("WinHttp.WinHttpRequest.5.1") url = args(0) target = args(1) WScript.Echo "Getting '" & target & "' from '" & url & "'..." http.Open "GET", url, False http.Send status = http.Status If status <> 200 Then WScript.Echo "FAILED to download: HTTP Status " & status WScript.Quit 1 End If Set adoStream = CreateObject("ADODB.Stream") adoStream.Open adoStream.Type = 1 adoStream.Write http.ResponseBody adoStream.Position = 0 Set fileSystem = CreateObject("Scripting.FileSystemObject") If fileSystem.FileExists(target) Then fileSystem.DeleteFile target adoStream.SaveToFile target adoStream.Close

Run it like this:

> cscript //Nologo download.vbs urlToGet pathAndFilenameToSaveAs > cscript //Nologo download.vbs http://example.com blah.html

Not bad. In fact, with this tool, we already have what we need to download files from within batch. Just invoke the script from a batch file, and you're good.

But there are still some problems:

First of all, I'd like to be able to give users instructions that aren't prepended with cscript. Plus, I don't particularly feel like continuing down this path of trying to remember how to use VBScript. So, even though batch is hardly a VB-killing language, I would like to be invoking any VBScript code from a batch file.

But that leads to another problem. Now I have, at a minimum, two distinct files: A batch file and a VBScript file. This means I'll need the user to download two files, or make them download and extract a zip, or make a self-extracting archive which violates the "no custom prebuilt binaries" goal. Is there any way out? Without sacrificing any of my goals?

Step Two: Downloader Ex Machina

Like Unix, the Windows command line can redirect output to files. Use > to overwrite a file, or >> to append:

> echo First line > file.txt > echo Second line >> file.txt > type file.txt First line Second line

Do you see where I'm going with this?

A common trick in the Unix world, we can use echo and file redirection to generate a text file on-the-fly. A text file such as...a VBScript!:

@echo off rem This is file: hello.bat echo WScript.Echo "Hello world" > hello.vbs cscript //Nologo hello.vbs

Run that batch, and it will create the following VBScript hello world:

WScript.Echo "Hello world"

Then the batch file invokes the VBScript file it just created, and "Hello world" is printed! We've just embedded a VBScript tool into a batch script.

Now we have everything we need to download a file using nothing more than a one-file batch script. All we do is embed the VBScript downloader tool into batch (using the caret ^ to escape any characters echo has trouble with):

@echo off rem Windows has no built-in wget or curl, so generate a VBS script to do it: rem ------------------------------------------------------------------------- set DLOAD_SCRIPT=download.vbs echo Option Explicit > %DLOAD_SCRIPT% echo Dim args, http, fileSystem, adoStream, url, target, status >> %DLOAD_SCRIPT% echo. >> %DLOAD_SCRIPT% echo Set args = Wscript.Arguments >> %DLOAD_SCRIPT% echo Set http = CreateObject("WinHttp.WinHttpRequest.5.1") >> %DLOAD_SCRIPT% echo url = args(0) >> %DLOAD_SCRIPT% echo target = args(1) >> %DLOAD_SCRIPT% echo WScript.Echo "Getting '" ^& target ^& "' from '" ^& url ^& "'..." >> %DLOAD_SCRIPT% echo. >> %DLOAD_SCRIPT% echo http.Open "GET", url, False >> %DLOAD_SCRIPT% echo http.Send >> %DLOAD_SCRIPT% echo status = http.Status >> %DLOAD_SCRIPT% echo. >> %DLOAD_SCRIPT% echo If status ^<^> 200 Then >> %DLOAD_SCRIPT% echo WScript.Echo "FAILED to download: HTTP Status " ^& status >> %DLOAD_SCRIPT% echo WScript.Quit 1 >> %DLOAD_SCRIPT% echo End If >> %DLOAD_SCRIPT% echo. >> %DLOAD_SCRIPT% echo Set adoStream = CreateObject("ADODB.Stream") >> %DLOAD_SCRIPT% echo adoStream.Open >> %DLOAD_SCRIPT% echo adoStream.Type = 1 >> %DLOAD_SCRIPT% echo adoStream.Write http.ResponseBody >> %DLOAD_SCRIPT% echo adoStream.Position = 0 >> %DLOAD_SCRIPT% echo. >> %DLOAD_SCRIPT% echo Set fileSystem = CreateObject("Scripting.FileSystemObject") >> %DLOAD_SCRIPT% echo If fileSystem.FileExists(target) Then fileSystem.DeleteFile target >> %DLOAD_SCRIPT% echo adoStream.SaveToFile target >> %DLOAD_SCRIPT% echo adoStream.Close >> %DLOAD_SCRIPT% echo. >> %DLOAD_SCRIPT% rem ------------------------------------------------------------------------- cscript //Nologo %DLOAD_SCRIPT% http://example.com blah.html echo File downloaded via batch!

Nice!

Read more


One D Annoyance: Conflicting UFCS and opDispatch

I love D's UFCS. I find D's opDispatch questionable (particularly in comparison to opIndex(string)). Unfortunately, opDispatch takes precedence over UFCS (And does so silently, annoyingly enough).

The consequence is UFCS cannot be used on most data structures that employ opDispatch. At least not without modifying the data structure's opDispatch itself - which defeats much of UFCS's point of adding "member" functions to a data structure without actually modifying the data structure itself.

I hate that. And it makes me hate opDispatch, too.

Read more


Dispelling Common D Myths

As a frequent user and fan of the D programming language, I've noticed a number of misunderstandings and stumbling blocks that frequently trip up newcomers to the D scene.

These are perfectly understandable confusions. Many of them have very legitimate historical causes, so it's unsurprising that certain outdated or inaccurate beliefs persist. I take these as areas where the D community could communicate better to the outside programmer community, so allow me to explain:

D has IDEs

There was a time when D didn't have much IDE support beyond syntax highlighting. This is no longer true. If you like fully-featured IDEs, there are three main options, all of them actively supported:

DSource is dwindling, but D is more active than ever

Every few months, the D community hears something like this: "Is D dead? I went on DSource and everything looked old and unmaintained, the forums seemed inactive, so I assumed D was dying."

DSource was the de-facto project-hosting site for D projects. Note: Was. These days, most of the active projects have moved over to GitHub and BitBucket. In fact, even the repositories for the official D compiler and it's standard library have been hosted on GitHub for well over a year. And in that time, contributions and growth have significantly accelerated, not declined.

There had been updates in the works for DSource to address the issue of easily finding the active projects amongst the dead ones (keep in mind, any free open-source project hosting site is inevitably bound to accumulate many dead projects). But with the incredible recent popularity of GitHub and BitBucket, such an update to DSource would be of minimal value.

It does, however, bother me a bit to say such things about DSource. I've always greatly appreciated DSource, and it was a fantastic thing to have back in the D1 days before GitHub and BitBucket had become everyday names for almost any open-source programmer. The site, bandwidth and hosting were, and still are, very graciously donated to the D community free-of-charge, so I hate to speak of DSource in a manner that sounds like a eulogy. But nonetheless, even though DSource usage is now minimal, D is not only very much alive, it's rapidly growing.

As for finding active D projects, in addition to ordinary search engines, I recommend the D Wiki. Admittedly, we haven't been as good about maintaining the wiki's list of projects as we should have been, but I hereby pledge from now on to do my part, and I'll nag other D users to do the same ;)

UPDATE 2012-12-12: In order to aid and encourage updating, D's wiki has recently moved from http://www.prowiki.org/wiki4d/wiki.cgi to http://wiki.dlang.org, and is now built upon MediaWiki (the same engine used by Wikipedia) instead of the dwindling ProWiki which a number of contributers have found awkward to use. The D community has also taken this opportunity to purge the outdated cruft from the wiki and update it. So D's wiki is indeed progressing!

The D1/D2 split is no more

D2 is where it's at. D2 has already become the stable branch, D1 is a relic. Forget D1, stick a fork in it, it's dead.

And when I say "dead", I don't mean Python 2 "dead": I mean that practically nobody is using D1 anymore. Everyone's already on D2, even the stragglers. D1 is so unused that official support will end at the close of this year, 2012 (and that was announced a year ago). Nobody cares about D1, nobody uses it. It's over.

So, there is no D1/D2 split. There is only D2.

(EDIT: I may have overstated this point. See the comments below.)

Phobos is D's standard lib, but what's up with Tango?

You may have heard about a "Phobos vs Tango" split. In retrospect, that was indeed a misstep for D, but the issue was recognized and fixed. First the summary: Phobos is D's standard lib, period. Tango is now an optional but Phobos-compatible third party library. That's all there is to it.

But that wasn't always the case. Here's the history, for anyone interested:

Back in the early D1-days, back even before Andrei Alexandrescu had come on board, D's standard library "Phobos" was in a very rough, incomplete state. This was because it was being developed entirely by one person (D's creator, Walter Bright). Unfortunately, he was too busy developing the language and compiler to be able to fully flesh-out the standard library (which was, due to various reasons, not entirely open at the time).

So a group of highly talented developers got together and undertook the admirable task of creating a complete standard library. This was called Tango, and it was so good, and so much better than the incomplete (at the time) Phobos, that it became the de-facto standard library.

Unfortunately, in order to work well, Tango needed to replace some of the very-low-level runtime portions of Phobos. This meant Phobos and Tango were incompatible - you had to choose between one or the other, not both. This, quite understandably, became a giant PR disaster.

Meanwhile, Phobos began transitioning to open-source, Andrei Alexandrescu joined up and became Phobos's leader, and Phobos finally started getting fixed and fleshed-out. And it was getting very good in its own right. But this naturally didn't help the "Phobos vs Tango" issue. Admittedly, it may have been a misstep in D's history. But fortunately, the D community heard the "Two standard libs?!?" complaints loud and clear, and set out to fix it.

At this point, D2 was underway as the main "unstable" (at the time) development branch (while D1 had become the stable "non-breaking-changes-only" branch). So for D2, the low-level runtime stuff that was creating incompatibility between Phobos and Tango was factored out and dubbed Druntime. In D2, Phobos and Tango *both* use Druntime, so Phobos and Tango are now fully compatible. There is no more split.

Which should you use? Phobos, unless you have some specific reason to pull in Tango as well. After all, Phobos is the standard library.

Why might you want to use Tango? Same reasons as any other third-party library: If you like the design of it, for example. Tango's design has a very Java-flavor, so Java users may like it. Or if you find something in Tango that's not in Phobos. For example, Tango has the world's fastest XML parser. Phobos's XML library, on the other hand, is the one module in Phobos that's known to still be in desperate need of a rewrite and might get removed. (Don't worry, the rest of Phobos is fantastic.)

D is open source

There are three main D compilers:

  • DMD: Official reference compiler
  • GDC: Uses GCC and is in the process of being merged into GCC mainline.
  • LDC: Uses LLVM.

GDC and LDC are fully open-source, period, and are even in certain Linux package repositories, and not in the non-free sections.

The standard library and runtime, Phobos and Druntime, are OSI-approved Boost-licensed.

DMD's entire source (as well as the standard library and runtime) is publicly available on GitHub. The front-end, which is shared with GDC and LDC is OSI-approved Artistic-licensed (EDIT: It's also dual-licensed under GPL).

The only thing that isn't strictly OSS is the backend of DMD, because the rights are licensed from Symantec. But the source for it is publicly available on GitHub and open for pull requests. Worried about redistribution? Don't be: Just ask Walter. He may be under obligation to require his permission, but it's only a technicality. Ask him, and he'll grant permission. He hasn't been known not to. And note, that's only for DMD, and specifically DMD's backend. Everything else is fully-OSS including two complete D compilers: GDC and LDC.

D is open-source. It wasn't always, but it definitely is now.

D allows manual memory management

D may have a garbage collector as standard, but that doesn't mean you can't control it, stub it or replace it or use manual memory management.

D supports pointers (neatly limited to a memory-safe subset of operations if you're using @safe mode) and calling C functions. So you can call malloc/free, and stick anything you want in the resulting memory using the emplace functions. Or you can use stack-allocated auto-scoped classes. Or reference counting. Or no-clutter RAII. Additionally, there's a whole custom-allocator system in the works.

Static-typed does NOT mean unproductive

D may be static-typed, but that shouldn't make you think "C++ and Java":

% cat funWithRanges.d import std.algorithm; import std.range; import std.stdio; void main() { // All done lazily: auto squares = sequence!((a,n) => n^^2)(0); auto fibonacci = recurrence!((a,n) => a[n-1] + a[n-2])(1, 1); auto fibEven = fibonacci.filter!(x => x%2 == 0)(); foreach(v; zip(squares, fibonacci, fibEven).take(6)) writeln(v[0], "\t", v[1], "\t", v[2]); } % rdmd funWithRanges.d 0 1 2 1 1 8 4 2 34 9 3 144 16 5 610 25 8 2584

And it's not just clean and fast, it's also safe and correct.

Plus there's some nifty concurrent processing toys, easy templates and metaprogramming, and the usual lineup of expected modern niceties.

Read more


Top D Features I Miss In C++

I've spent the last month or so on a project that, due to factors beyond my control, must be in C++ and not D.

A little of my background first: I used C/C++ as my primary language in the late 90's and early 2000's. Liked it at the time, but then got fed up certain aspects and went looking for alternatives. Long story short, I found D, fell in love with it, and have been using it extensively for years.

Now that I'm back in C++-land (hey, it beats the hell out of writing a whole game entirely in a dynamic service/server-compiled toy from the same jokers folks who brought us the wonderful Flash), I've built up a list of the top things I miss from D when using C++. There's plenty of other great stuff in D that I miss, but these are the ones...so far...that are proving to be the most painful to live without in the particular project I'm working on (An iOS/Android puzzle-ish game). Other projects would likely have very different lists, of course.

Incidentally, this also serves as a deeper explanation for anyone who didn't understand the vague heckling of C++ in my previous post.

Top D Features I Miss In C++

  1. Proper module system: One of the main things that drove me away from C++ in the first place. The header-file/text-inclusion hack is a colossal, anachronistic pain in the ass. There are so many problems with this one issue alone, I'm not sure they're even worth listing. But I will anyway because they deserve public ridicule:

    C++'s "Module" System Sucks

    • #ifndef _FILENAME_H_: All the reason you need to know C++'s module system sucks. Retarded hack.

    • Identifiers prefixed with psuedo-module vomit: Let's see... CIwFVec4... CIwGameActorImage... WTF? Can I haz FVec4 and ActorImage, plz? Yea, I know there's namespaces, but not everyone seems to use them. Somehow I have a feeling there's a good reason for that - besides just easier interfacing with D.

    • DRY? What's DRY? Derp derp durrr....

    • Scrambled modules! Let's chop up our module and play "What goes where?!?" Implementation files: non-inlined function bodies, non-member variables (which aren't evil globals in a language with proper modules), and private preprocessor directives. Header files: member variables, inlineable function bodies, public preprocessor directives, member accessibility (public/private), non-DRY duplication of non-inlined function signatures, plus includes and forward declarations that should be private but must be leaked out due to something else in the header needing to use them. Whee!

    • Header files are interface documentation? LIES! Seriously, look at your header files. You're really going to try to tell me that only contains the public interface? Then what's that private: section doing in there? And that forward declaration for an external class? If you want automatic documentation, run a damn documentation generator. They exist.

    • Headers affected by whatever headers were included before it: Hygiene? What's hygiene? And why is this compiling so slow? Durrr...I wonder why?

    • Fuck precompiled headers: Talk about "solving the wrong problem".

    • No RDMD (automatic dependency finding): Every...fucking...source file must be manually specified. I remember to do this about half the time.

    • And the #1 reason C++'s "module" system sucks: What is this, 1970?

  2. Actual properties:

    foo->setX(foo->getX() + 1); // Suck my nutsack, C++

  3. Metaprogramming that doesn't involve a text preprocessor or gobs of excessive template instantiations.

  4. Sane type-name syntax: In C++, how do you spell int*[]* delegate()[]* (Ie, a pointer to an array of delegates which take no params and return a pointer to an array of int pointers)? Wrong! The correct answer is "Fuck you, I'm not attempting that shit in C++!"

  5. Type deduction: Unfortunately, Marmalade doesn't yet support C++11, so I don't even get auto.

  6. Closures, lambdas, nested functions: There's a good reason Qt in C++ requires a special preprocessor. (Yea, I'll care about C++11's features when I can rely on them actually existing in my compiler.)

  7. No forward declarations: Was I wrong before? Maybe this is still 1970?

  8. Actual reference types: And no, I don't mean Foo&.

  9. Non-schizo virtual: C++'s member funcs are non-virtual by default...except the ones that are virtual by default and can't be sealed as final. WTF? WTF indeed. (Yes, I do understand how it works, but it works stupidly.)

  10. Default initialization: Granted, I'd rather be told at compile-time about possibly using non-inited vars (ie, C#-style)...But garbage-initialization? Screw that. Especially for pointers, I mean, fuck, really?! Pain in the damn ass.

  11. Fast compilation: Hooray for the world's slowest-compiling language! Whee!!

  12. Polysemous literals: C++ can barely figure out that 2 can be a float. Gotta babysit it with 2.0f. Great.

  13. Ranges: Fuck iterator pairs.

  14. Named immutables/constants that actually exist in the real code, not just the preprocessor.

  15. Designed by someone who actually fucking understands proper engineering.

Things I'm surprised I don't miss yet (but may still miss later and would undoubtedly miss if my project were for a different domain or maybe even just using different engine):

  • Slices and string/array manipulation: Fuck null-terminated strings, fuck pointer/length pairs, and fuck everything in string.h.

  • Associative arrays: Just works. Any key type. No syntactic bullshit.

  • Scope guards: Also known as "RAII that isn't a contrived syntactical kludge".

  • GC: You can pry manual memory management from my cold dead hands, but that doesn't mean I always wanna fuck with it.

  • Foreach: I'm still convinced foreach(i; 0..blah) is essential for any modern language, but my prior experience with C/C++ seems to have left for(int i=0; i<blah; i++) irreparably burned into my brain.

And ok, to be perfectly fair to C++, let's turn things around a bit...

Things from C++ I miss when I go back to D:

  • .......
  • Ummm.....
  • Not a fucking thing.

UPDATE (2012-09-12): Added "RDMD" to reasons C++'s module system sucks. Can't believe I forgot that before, that's a big one.

Read more