A pedant that hangs out in the dark corner-cases of the web.

Tuesday, June 28, 2011

The "Moderated" Response to IEBlog's Anti-Auto-Update Screed

I submitted a reply to A Browser for All Windows Customers: it’s about and, not or - IEBlog - Site Home - MSDN Blogs, but it was "moderated" away. Apparently, Microsoft only approves comments by sycophants and strawmen.

Here is the comment, for anyone curious:

So foot-dragging is a feature?

That just seems like a rationalization for not supporting standards in the coming years (HTML5 inputs, e.g.), and being the holdout on auto-upgrades, the only hope many web developers had of seeing reasonable standards support (as opposed to kludgy workarounds) before the end of their career.

Hopefully Chrome Frame will make some inroads for the sake of developers, upon whose back the "great" IE experience comes. (Can someone from Microsoft supply, from their vast compatibility stats, how many top Internet sites are likely to use hardware rendering vs. how many take date inputs?)

Don't expect a lot of sympathy just because the job is impossibly big. Microsoft used anti-competitive practices to make IE the default browser, and has now found itself in the position of having to support up to FOUR rendering engines per browser per OS per service pack. And it's only going to grow, this thankless position of "infrastructure". More rendering engines will accumulate geometrically year after year (in a product that doesn't even show a profit) until Microsoft just cannot sustain any more and has to make some tough decisions about backward compatibility.

I think the track record shows that this realization often comes quite late in Redmond.

And another "moderated" comment, from The Perils of User-Agent Sniffing, 2011 Edition - EricLaw's IEInternals - Site Home - MSDN Blogs:

I'm surprised and disappointed that Google is using UA sniffing, but do you really expect all websites to understand the dozens of different combinations of rendering engine modes, browser modes, and document modes, and the endless HTTP extensions (X-XSS-Protection, DNT, X-UA-Compatible, X-Content-Type-Options, X-Frame-Options) required to get IE working?

Can anyone really be blamed for wanting to just walk away from IE, given that we've all just been slapped in the face again with the assertion that the web may only progress in 10-year increments?

Monday, May 23, 2011

F# Source that runs interactively or compiles

Here's a simple way to create code that you can run with FSI or compile with FSC:

#if INTERACTIVE
// any #load, #r, or other fsi directives, e.g.:
#r "System.Configuration.dll"
#else
module ModuleName
#endif

// … code …

let main (args:string[]) =
// … main body …

#if INTERACTIVE
main fsi.CommandLineArgs.[1..]
#else
[<EntryPoint>]
let Main args =
try
main args ; 0
with
| ex -> printfn "%s" (string ex) ; 1
#endif

Name the file with a .fsx extension, then you can compile it normally, or run it as a script with fsi filename.fsx -- args, or #load it from within FSI!

Thursday, April 07, 2011

An F# mutually-tail-recursive CSV record parser.

I've been really enjoying F# lately. Functional, concise, fast, fun. Here's a simple CSV parser. It's meant to be used ad-hoc, rather than some of the more full-featured CSV parsers that require what I'd consider to be an unrealistic level of premeditation to set up the columns and datatypes at design time. This one is a simple sequence of lists of, or mapped headers to, string values.

open System
open System.IO

// An F# mutually-tail-recursive CSV record parser.
// See the spec at http://creativyst.com/Doc/Articles/CSV/CSV01.htm
let rec csvrecord sep (tr:#TextReader) record (line:string) i =
if i = line.Length then record @ [""]
else
match line.[i] with
| '"' -> csvfield sep tr record "" line (i+1)
| ' ' | '\t'-> csvrecord sep tr record line (i+1)
| c when c = sep -> csvrecord sep tr (record @ [""]) line (i+1)
| '=' when line.[i+1] = '"' -> csvfield sep tr record "" line (i+2) // Excel compatibility
| _ -> // unquoted field data
let fs = line.IndexOf(sep,i)
if fs = -1 then record @ [line.Substring(i).TrimEnd()]
else
csvrecord sep tr (record @ [line.Substring(i,fs-i).TrimEnd()]) line (fs+1)
and csvfield sep (tr:#TextReader) record field (line:string) i =
if i = line.Length then csvfield sep tr record (field+"\n") (tr.ReadLine()) 0
elif line.[i] <> '"' then
let q = line.IndexOf('"',i)
if q = -1 then csvfield sep tr record (field+line.Substring(i)+"\n") (tr.ReadLine()) 0
else csvfield sep tr record (field+line.Substring(i,q-i)) line q
elif i = line.Length-1 then record @ [field]
elif line.[i+1] = '"' then csvfield sep tr record (field+"\"") line (i+2)
elif line.[i+1] = sep then csvrecord sep tr (record @ [field]) line (i+2)
else // not an escaped quote and not end of field; try to recover by appending trimmed unquoted field data
let fs = line.IndexOf(sep,i+1)
if fs = -1 then record @ [field+line.Substring(i).TrimEnd()]
else csvrecord sep tr (record @ [field+line.Substring(i,fs-i).TrimEnd()]) line (fs+1)

let csvrows sep (filepath:string) = seq {
use sr = new StreamReader(filepath)
while not sr.EndOfStream do
yield csvrecord sep sr [] (sr.ReadLine()) 0
}

let csvrecords sep (filepath:string) = seq {
let lists = csvrows sep filepath
let headers = Seq.head lists
for vals in (Seq.skip 1 lists) do
yield List.zip headers vals |> Map.ofList
}

Wednesday, February 16, 2011

Then What? elif, elsif, elseif, or else if?

"Else if" in multiple languages:
  • elif : Python, bash, and F#
  • elsif : Perl and Ruby
  • elseif : PHP and PowerShell
  • else if : C, C++, C#, JavaScript, and just about everything else (if)
  • ELSE IF : T-SQL (case-insensitive)
  • ElseIf : VB, VBScript, and VB.NET (case-insensitive)