ImagePrinter is a Windows printer driver that prints to multiple image files (e.g PNG or JPG).
... until the collector arrives ...
2008-12-18
2008-12-01
Browsershots
browsershots.org provides a free online service that will display screenshots of a given URL on up to 60 different browsers.
2008-11-28
Product Aggregation in SQL Server
Ever wanted to write something like this in SQL Server:
SELECT PRODUCT(MYCOLUMN) FROM MYTABLE
Well, wish no more:
DECLARE @P FLOAT
SET @P = 1
SELECT @P = @P * MYCOLUMN FROM MYTABLE
SELECT @P
... provided you can use the query in a context that permits T-SQL that is (e.g. not in a view or a subquery). Note that you can perform arbitrary aggregations using this technique (say, summing while respecting null contagion, concatenating strings... the mind boggles).
2008-11-18
How Many Agile Product Guys?
I was curious how many of the Agile Manifesto guys had a "product" background. By that I mean that they have worked in a product shop at least more recently than they got into the "agile" game. Here is the score:
- Mike Beedle - don't think so, his Agile bio suggests that he has been consulting since the 90's
- Arie van Bennekum - don't think so, from his Agile bio
- Alistair Cockburn - no, according to the bio on his site
- Ward Cunningham - maybe, from his Agile bio -- can't tell from other online sources
- Martin Fowler - no, from the bio on his site
- Jim Highsmith - no, from the bio on his site
- Andrew Hunt - no, from the bio on his site
- Ron Jeffries - no, from the bio on xprogramming.com
- Joe Kern - no, despite the fact that his bio at immuexa talks of Compuware's OptimalJ "product team"
- Brian Marick - maybe (as a tester?), from his bio at exampler
- Robert C. Martin - no, from his bios at Object Mentor and his blog
- Ken Schwaber - no, from his Agile bio
- Jeff Sutherland - yes, from his Agile bio
- Dave Thomas - don't know
So, we have 1 yes, 2 maybe yes, 2 maybe no, 8 no and 1 unknown. Let's split the difference on the uncertain ones and say 10.5 no to 3.5 yes.
2008-11-14
JVM Heap Dump Options
On the Sun JVM, you can tell it to perform a heap dump automatically when an out-of-memory error occurs using these arguments:
-XX:-HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=c:\oomdump.hprof
There are many more Java HotSpot VM options.
2008-10-21
CodaServer
CodaServer is the beginnings of an open source middleware system that adds business rules and workflow to a SQL database. A key feature is a form which is characterized as "tables with workflow".
2008-09-22
SQL Server 2000 vs LOG and SQRT
If you attempt to take the LOG or SQRT of a negative number in SQL Server 2000, it fails quietly but catastrophically. Should a query attempt to perform one of these operations, the result set is empty -- all rows are discarded. No error is reported, neither to the client nor in the SQL Server logs.
2008-09-21
OpenLaszlo
OpenLaszlo will now compile its applications down to DHTML (in addition to the Flash that it has always done).
2008-09-12
Quick Highlighter
Quick Highlighter is an on-line service that can generate pretty looking output for code in many languages. My favourite feature of this service is that it hyperlinks built-in constructs to their reference pages -- especially for less popular languages like Haskell.
2008-09-06
2008-09-04
OpenSourceCMS
OpenSourceCMS is a web site that hosts sandboxes for many of the open source CMS systems. It provides a painless way to try out the various products.
2008-08-27
Scriba
Scriba is a Mathematica-style document-centric interface to BSF languages. It ships with BeanShell, HTML, JRuby, and JScheme pre-installed. Any JSR-223 compatible engine can be plugged in. See, for example, the list of such engines in the java.net scripting project.
2008-08-20
2008-08-09
Excessive Hardware Interrupts
Windows recently told me it had found a bad block on my disk drive. I ran a disk check and told it to fix bad blocks. Presumably, the bad block had been spared out. However, my computer's performance was awful. I tried the usual dance -- clean up, defrag, ensure the page file was contiguous in a good spot -- but performance was still awful.
CPU usage was running at a background level of 10-20%. Process Explorer attributed this CPU to "Hardware Interrupts". A bit of Googling led me to this blog entry:
Little-Known Tweak to Boost Hard Drive Performance!
In short, after Windows has noted six I/O errors on a controller, it pins that controller to programmed I/O mode (PIO). You can check this by looking at the properties of the disk controller in the Device Manager. The only way to re-enable DMA mode is to perform some registry hacks under the key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96A-E325-11CE-BFC1-08002BE10318}
Find the sub-key associated with the controller in question (e.g. the primary IDE channel). Then:
- delete
MasterIdDataCheckSum
(if present) - delete
SlavedIdDataCheckSum
(if present) - add
ResetErrorCountersOnSuccess
(DWORD) = 1 (if desired) - set any or all of the following capability masks to 0xFFFFFFFF (if
present):
MasterDeviceTimingMode
MasterDeviceTimingModeAllowed
SlaveDeviceTimingMode
SlaveDeviceTimingModeAllowed
UserMasterDeviceTimingModeAllowed
UserSlaveDeviceTimingModeAllowed
- reboot
After rebooting, check to see whether the relevant controller has reverted to DMA mode. If so, your problem is probably solved (unless the hardware is truly gacked).
2008-08-06
SQL Server Comments vs Line Terminators
If you use the '--' comment syntax in SQL Server, the comment extends to the end of the line. The question is: what constitutes the end of the line. It turns out that SQL Server does not count a single return character as the end of line, so the following line(s) might be gobbled up into the comment.
It would seem that lines that end solely with a return character wouldn't happen in practice, at least on Windows. However, if can happen if you are using the combination of HTA, DOM, Javascript and ADO. If you extract the text content of an HTML element using DOM, then line terminators that are expressed as \r\n on disk are converted to \r in memory. It is necessary to fix up such line endings before feeding the string to ADO if the SQL text contains any '--' comments.
2008-07-31
JUnit Gotcha
In JUnit 4, if you use the version of assertEquals that compares two objects, and those objects happen to be subclasses of Number, the framework converts them to long before comparing them. This is broken for any non-integral type since it will neglect the fractional part.
Just to make matters worse, if you attempt to compare two floating point numbers using assertEquals and you forget to add the 'delta' argument, then once again you will get the object-version of the method and the comparison will be invalid. This is a regression from the old JUnit which predated auto-boxing and the compiler would moan about mismatched argument types. It is hard to believe, but this unit test passes:
@Test
public void test() {
assertEquals(1.2, 1.3);
}
Functional Java
Functional Java is a Java library inspired by Scala and Haskell. It anticipates the addition of first-class functions to Java 7, especially if it follows the BGGA Closure proposal.
Closures
It is increasingly bugging me how the term "closure" is becoming synonymous with "function literal", especially in the Java community now that it is just discovering functions. People seem to forget that Pascal had closures in 1974, but it didn't support function literals. I thought that Algol had closures first, but according to Wikipedia Scheme was the first in 1970. Naturally it inherited function literals from LISP. Of course, Scheme has the definitive implementation of closures which are not restricted to stack-based lifetime nesting. This is unlike Pascal and practically every other language under the Sun which thinks that the stack is fundamental -- nobody in Java-land is talking about that. At least BGGA has the UnmatchedNonlocalTransfer exception. This is an improvement over Smalltalk where the VM would just crash.
I'm sure Algol had closures. Maybe in Algol 60 but certainly by the time of Algol 68.
2008-07-21
2008-07-20
Joe Armstrong on Erlang
InfoQ has an interesting one hour lecture by Joe Armstrong: Erlang - software for a concurrent world.
2008-07-03
2008-07-01
2008-06-30
SQL Server 2000 vs Recursive Functions
In SQL Server 2000, if you attempt to alter an existing recursive function so as to change the number of parameters, you will receive an error message complaining that you are passing the wrong number of arguments to the function. This appears to be because SQL Server is checking against the old definition of the function being defined.
2008-06-20
Fiddler
Fiddler is a TCPMON-like web debugging proxy for the .NET ecosystem. If you want to perform port-forwarding like TCPMON, you can either add a registry entry like this:
HKCU\SOFTWARE\Microsoft\Fiddler\ReverseProxyForPort=target port (DWORD)
or enable Tools/Fiddler Options/Allow remote clients to connect and then add an OnBeforeRequest handler in Rules/Customize Rules:
if (oSession.host.toLowerCase() == "webserver:8888") oSession.host = "webserver:80";
2008-06-19
Data Storm
Data Storm is a lightweight database browser intended to be invoked in-line in a Java unit test. It is useful for debugging database unit tests that perform a rollback after the test.
2008-06-13
Java Bean Introspector vs Boolean
The Java bean introspector returns null for the read method for a property whose type Boolean (boxed) and whose getter follows the is... pattern. JAXB names such properties following that pattern.
2008-06-11
Visual Studio XSD Tool vs XML Schema
The Visual Studio XSD tool cannot handle an XML Schema that uses a repeating element with the same name at two distinct places. For example, it cannot handle this schema (in XQuery notation for brevity):
root {
elementA {
problemElement {
name
}
},
elementB {
problemElement {
name
}
}
}
The element named problemElement causes the problem. If you attempt to generate C# code for this schema using the XSD tool, it all works. But if you try to generate a dataset, you an error like:
Error: There was an error processing 'myproblematic.xsd'.
- The same table (ProblemElement) cannot be the child table in two nested relations.
The solution is to rename one of the problematic elements to reflect the context (sigh).
I have a minimal xsd that demonstrates the issue:
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="urn:tns" xmlns:tns="urn:tns" > <xs:element name="Root" type="tns:Root"/> <xs:complexType name="Root"> <xs:sequence> <xs:element name="ElementA"> <xs:complexType> <xs:sequence> <xs:element name="ProblemElement"> <xs:complexType> <xs:sequence> <xs:element name="Name" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="ElementB"> <xs:complexType> <xs:sequence> <xs:element name="ProblemElement"> <xs:complexType> <xs:sequence> <xs:element name="Name" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:schema>
And here is the command to process it:
C:\VS.NET2003\Common7\Tools\vsvars32.bat
xsd /d dotnet-xsd-bug.xsd
2008-05-31
Y-Combinator Explained Using Javascript
We take recursion for granted in most languages. Consider the factorial function, in Javascript:
function f(n) {
return (n < 2) ? 1 : n * f(n-1)
}
This implementation relies on the fact that the name f being defined is the same as the f in the definition. If you think for a minute about how a compiler would arrange this, you are likely to come up with an imperative solution. For example, the compiler might leave a placeholder for f in the compiled definition and then update it to point to itself once the body has been compiled.
Systems like the lambda calculus, being purely functional, do not admit of such imperative solutions. So how do you express recursion functionally?
One answer is a technical trick called the Y-combinator. Let's start by writing a variation of the factorial function:
function f(r) {
return function(n) {
return (n < 2) ? 1 : n * r(n-1)
}
}
Instead of taking an integer and returning an integer, this new f takes a function and returns a function. The returned function can compute the factorial of an integer -- provided r was bound to a suitable function that ensures the requisite recursion.
What is the proper argument for r? How about f?
f(f)(10)
It looks promising, but it won't work. Look again at the definition of f. r must accept an integer as its argument, but we have passed f which expects a function. This is trickier than it looks. What we need is something like:
f(f(f(f(f(f(...))))))(10)
Enter the Y-combinator. It is used like this:
Y(f)(n)
which evaluates to:
f(Y(f))(n)
that is:
f(f(f(f(f(f(...))))))(n)
That's easy to say. But has does one write this mythical function Y? I can't answer that, but Alonzo Church could. Here's the definition he somehow puzzled out, in lambda notation:
λf . (λg . f (g g)) (λg . f (g g))
Applying Y to f, the evaluation sequence is as follows:
(λf . (λg . f (g g)) (λg . f (g g))) f
(λg . f (g g)) (λg . f (g g))
f ((λg . f (g g)) (λg . f (g g)))
f (f ((λg . f (g g)) (λg . f (g g))))
f (f (f ((λg . f (g g)) (λg . f (g g)))))
f (f (f (f ((λg . f (g g)) (λg . f (g g))))))
...
This has the desired property. Here is Y expressed in Javascript, along with the almost-recursive definition of f and a test case:
function Y(f) {
return function(g) { return function(n) { return f(g(g))(n) }}(
function(g) { return function(n) { return f(g(g))(n) }}
)
}
function f(r) {
return function(n) { return n < 2 ? 1 : r(n-1) * n } }
alert(Y(f)(10))
Nifty, huh? For those who want to play along in Scheme:
(define Y
(lambda (f)
((lambda (g)
(lambda (n)
((f (g g)) n) ))
(lambda (g)
(lambda (n)
((f (g g)) n) )))))
(define f
(lambda (r)
(lambda (n)
(if (< n 2) 1 (* n (r (- n 1)))) )))
((Y f) 10)
2008-05-26
Equinox HttpContextManager Bug
There is a bug in the Eclipse Equinox implementation of HttpContextManager (version 1.0.0.v20070608). It throws an array out-of-bounds exception on line 91:
for (int j = 0; j < resourceMappingElements.length; j++) {
IConfigurationElement resourceMappingElement = resourceMappingElements[i];
i is the wrong index variable. It should be j.
This code will only work when there is only one context with no more than one resource mapping.
2008-05-23
eXist Redux
The eXist XML database system has come a long way. It now supports full XQuery and lots of HTTP interfaces. It provides two out three layers in the so-called XRX stack (REST and XQuery). Now how about a browser that does XForms to complete the stack?
The Third Manifesto
The Third Manifesto is Darwen and Date's latest take on the relational model. It attempts to eliminate the OO/relational impedence mismatch by fully supporting the relational model (in contrast, say, to the limited support in SQL).
2008-05-08
Google Chart API
Google provides a nifty service for generating charts, the Google Chart API. You can get charts like this...
... just by crafting up a special URL:
http://chart.apis.google.com/chart?chs=200x100&cht=lxy&chtt=A Google Chart&chd=t:10,20,40,60,80,100|99,50,15,125,300,43
2008-05-02
Hibernate Tuple Query Debugging
If you are using a Hibernate HQL query like select new MyClass(...) and Hibernate cannot find an appropriate constructor, the exception message does not tell you the types of arguments for which it was looking. You can find out by setting a breakpoint in org.hibernate.util.ReflectHelper#getConstructor(...).
Hibernate cannot find tuple classes that are inner classes.
2008-05-01
Broken Hibernate Tools for Eclipse
The Hibernate Tools 3.2.1.GA running in Eclipse 3.3.2 have problems.
The worst is that when you run your second HQL query, the IDE hangs. You can avoid the hang if you remember to close the previous result set pane first.
Also, the Hibernate Entity Diagram view is completely missing.
2008-04-30
Bug in Hibernate
In Hibernate 3.2.2, there appears to be a bug in org.hibernate.loader.custom.CustomLoader#scroll(). It calls the private method getHolderInstantiator():
static private HolderInstantiator getHolderInstantiator(ResultTransformer resultTransformer, String[] queryReturnAliases) {
if ( resultTransformer != null ) {
return HolderInstantiator.NOOP_INSTANTIATOR;
}
else {
return new HolderInstantiator(resultTransformer, queryReturnAliases);
}
}
The condition in the if statement appears to be reversed -- if a transformer is passed in it is ignored, otherwise it is used. This bug turned up because I had registered a result transformer on the containing query. It is still not fixed in the Hibernate source repository at the time of this writing.
The obvious workaround is to call the transformer yourself on each result row. Unfortunately you must pass a list of result aliases to the transformTuple method of the transformer. And how do you get that list? You call Query.getReturnAliases of course. But for an SQL query, you will get an UnsupportedOperationException, with the comforting message "SQL queries do not currently support returning aliases".
2008-04-28
Java Idioms for Hashing
It is common practice in Java for the calculation of a hash code to take every field into account, recursively descending into referenced objects. In contexts where performance matters, this practice can be harmful. The computation of the hash code in such fashion may actually be more expensive than a full equality check considering that hashing involves a lot of multiplications where equality testing involves only comparisons.
Hashing is also used to divide objects into buckets. For this purpose the extra cost is justified since one hash computation may eliminate many equality tests. However, it is frequently not necessary to hash the entire reachable object graph to get a good hash code. If an object's local non-reference fields show good variance in values across objects, it is adequate to hash them alone -- or even just a subset. The most problematic case is "algebraic types", where the objects may large consist only of references to other objects. Even in this case, one might still be able to get a decent hash by hashing only the object types a few levels into the object graph. Limiting the depth of the traversal is also a reasonable strategy if the reachable object graph contains circular references.
Again, these observations only really matter when performance is a large consideration. For small collections of objects from a small space, the extra think time is probably not worth the effort. But, once again, it is shown that hashing is difficult.
2008-04-25
SQL Server vs CREATE TRIGGER
Using SQL Server 2000, a CREATE TRIGGER statement must be the first statement in a batch. However, unlike other statements with that requirement, you cannot even put a SET XACT_ABORT ON statement in front of it.
2008-04-18
Determine File Extensions in Use
The following Mathematica code defines a function that lists all of the file extensions in use in a directory tree:
FileExtensionsInUse[directory_] := Module[{pattern="."~~Except["."|$PathnameSeparator]..~~EndOfString},
StringCases[#, x:pattern:>x] /. {{}->"", {x_}:>x} & /@
Select[FileNames["*", directory, Infinity], !StringFreeQ[#, pattern]&] //
Union
]
2008-04-17
Ant vs Command Line Properties
Ant 1.7 appears to be sensitive to the order of command line options. If you specify the build file (using -f) before specifying a property file (using -propertyfile), the build file will be loaded prior to loading the property file. Thus, property values within the property file will not override those in the build file. Reverse the order of the options if you want the property file to be loaded first.
2008-04-16
Mysterious Eclipse 3.3 Build Path Problems
Using Eclipse 3.3, I had a plug-in that failed to build with the error message complaining that a JAR on which it depends is missing. The JAR was listed as an explicit, workspace-relative, library entry. It was not listed in the plug-in manifest in any way.
I:
- verified that the destination resource existed
- deleted the library entry and re-added it
- cleaned and rebuilt the project
- refreshed all resources in the workspace
None of these actions corrected the problem. I eventually fixed it by temporarily adding the required JAR to the extra classpath entries in the plug-in manifest. As soon as I did this, Eclipse tried to rebuild the project but failed complaining that there were now duplicate entries for the errant JAR. I then removed the extra classpath entry that I had added and all was well. Net result: no change.
I do not understand either what was broken or how it was fixed. I can only imagine that Eclipse had some kind of cached information somewhere that finally got cleared out.
2008-04-11
Simulating Colour Blindness
Computerized simulation of color appearance for dichromats, by Hans Brettel, Francoise Vienot and John D. Mollon, is a paper that provides algorithms for transforming computer images so as to simulate the effects of various forms of colour blindness.
2008-04-05
2008-03-13
Extracting Mathematica Notebook Content
The following Mathematica expression will extract all non-input cells from a notebook and create a new notebook that contains only those cells:
NotebookWrite[CreateDocument[],
Cases[NotebookGet@EvaluationNotebook[],Cell[_,Except["Input"],___],Infinity] ]
Iterating Through Mathematica Notebook Cells
The following snippet will iterate through the all the cells in a Mathematica notebook and close all Input cells:
Module[{nb, cell},
nb = Notebooks["mynotebook.nb"][[1]];
SelectionMove[nb, Before, Notebook];
While[SelectionMove[nb, Next, Cell]; cell=NotebookRead[nb]; {}=!=cell,
If["Input" == cell[[2]],
SetOptions[NotebookSelection[nb], "CellOpen" -> True] ]
]
]
2008-03-10
Scala and Haskell Combinators
In Scala, I find the syntax used in for comprehensions a bit confusing. Specifically, the use of the keyword for. Clearly, this is a concession to simulating looping constructs from other languages, particularly looping over collections. The fact that for constructs compile to map, flatMap, filter and foreach reinforces this view. However, the facility is more general. Consider the use of for comprehensions in the Parser library. The code style looks more like a Haskell do block. It relies on the fact that the parser combinators return "collections" that are either empty or contain one element. Thus, the "loops" are really a chain of expressions, the chain being broken by the first parse failure. This is analogous to looking at an SQL inner join and realizing that the cardinality of all of the relations involved in the join have cardinality zero-or-one.
Haskell's do seems to suffer from a similar problem. The construct is intended to be used with the celebrated Monad type. But the word do suggests simple sequencing -- not general combinators. It doesn't help that the monadic unit operation is named return. No wonder people get confused by monads.
In both Scala and Haskell, I think that the mixed metaphors cause grief. At least in my case, the supposedly helpful choices of keywords made it harder to understand the deeper truth. In both cases, perhaps it would have been better to have two levels of abstraction: an upper level that uses only friendly keywords like for, do and return, and a lower level that only uses monadic or combinator terms. Keep the two worlds separate.
Why Java Makes Me Stupid
My recent work in Mathematica has re-awakened some of my LISP sensibilities -- intuitions that I lost while working in Java. What is it about Java that makes me forget about symbolic programming? Well, I suppose it would be nice if Java had:
- a symbol type
- a "data" syntax
- lightweight lists
- less verbose collection syntax (e.g. for operations like fold/reduce)
The list could grow longer, of course. Where are higher-order functions or even simple lambdas?
Having said all that, it is not impossible to do symbolic programming in Java. It is just unpleasant (contrast the LISP and Java LabEngines, for example). Also, the whole Java culture is "do this, then this, then this...", not "compose this and this and this". Java makes the function call a significant event. Not as significant as it was in the Fortran days, to be sure, but still way more significant than in LISP or Smalltalk or Mathematica or Haskell or Scala or ...
2008-03-08
Scala XML Book
The official Scala documentation for the XML facilities are poorly documented (just like everything else in the Scala library). However, the Scala XML Book fills in some of the blanks.
XMF
Ceteva's XMF is a container language that glues together code fragments written in many different languages, in a style reminiscent of C ASM blocks. It is hard to pin down the target application of XMF. The core language contains more than glue. "Undo" is a native concept, and there appears to be a sizable core library. The documentation emphasizes language-oriented programming and meta-modelling. Many language constructs are available to define DSLs.
2008-02-29
Virtual CloneDrive
Virtual CloneDrive is a convenient CD image mounter that masquerades as a permanent device.
2008-02-27
Alan Kay's Definition of OOP
From Meaning of "Object-Oriented Programming" According to Dr. Alan Kay:
OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I'm not aware of them.
This was written in 2003, long after the creation of C++ or Java.
2008-02-14
2008-02-12
PXSL
Parsimonious XML Shorthand Language (PXSL) is interesting both for what it does (provide a shorthand syntax for XML) and for how it is implemented (in Haskell).
SQL Server 2000 Functions vs. Usefulness
The SQL Server 2000 development team have really gone out of their way to make table-valued functions less than useful. Here, for example, is a function that will retrieve ancestors of a row in some kind of hierarchy table:
create function ancestors(@id int)
returns @t table(id int)
as begin
while 1=1 begin
select @id=(select parentId from hierarchyTable where id=@id)
if @id is null break
insert into @t values(@id)
end
return
end
But don't actually try to use this function:
select a.id, anc.id from hierarchyTable a
left join ancestors(a.id) anc on (1=1)
The alias 'a' is not visible in the argument to the function call. In fact, it appears that the only way to pass a non-constant value to a table-valued function is within a stored procedure.
Apparently, this is fixed in SQL Server 2005 using the new CROSS APPLY or OUTER APPLY join operators. Of course, SQL Server 2005 implements recursive queries using the WITH clause for SELECT statements, so such function shenanigans are less necessary:
WITH
data AS (
SELECT 'grandparent' AS id, CAST(NULL AS VARCHAR(MAX)) AS parent
UNION SELECT 'parent 1', 'grandparent'
UNION SELECT 'parent 2', 'grandparent'
UNION SELECT 'child 1', 'parent 1'
UNION SELECT 'child 2', 'parent 1'
UNION SELECT 'child 3', 'parent 2'
UNION SELECT 'child 4', 'parent 2'
)
, hierarchy AS (
SELECT 0 AS level, CAST(NULL AS VARCHAR(MAX)) AS parent, id
FROM data
WHERE parent IS NULL
UNION ALL
SELECT parent.level+1, child.parent, child.id
FROM data AS child
INNER JOIN hierarchy AS parent ON parent.id = child.parent
)
SELECT * from hierarchy
ORDER BY 1, 2, 3
2008-02-09
Parnas on Software Engineering
In a similar vein, some of David Parnas' lectures concerning software engineering can be found at the David Parnas Lecture Series at the University of Limerick.
Early LISP Paper
John McCarthy has put one of his seminal LISP papers up on the web as HTML: Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I.
2008-01-31
Vital and Pivotal
Vital is a Haskell implementation that takes a document-centered approach, much like a Mathematica notebook. Its successor, Pivotal, is a Haskell re-implementation of the Java original. Pivotal is only in the early stages. Both feel like incomplete implementations, but Vital in particular seems suitable for sandbox-style exploration of Haskell.
Implications of Non-Strict Functions
Here is a great little Haskell snippet that will wrench you out of imperative thinking:
notimperative x = (a,b,c,d) where
(a,b) = incr x c
(c,d) = incr d a
incr i j = (i+1,j+1)
The result of evaluating notimperative 1
is (2,5,4,3)
.
A pithier, but more obvious, version is:
notimperative2 x = (a,b) where
(a,b) = (b+1,x)
2008-01-29
2008-01-26
Sandboxie
Sandboxie is a Windows virtualization application that allows you to run arbitrary programs within an isolated sandbox. It prevents applications from making permanent changes to the true file system and registry. Apart from the security service that it may provide, it allows you to test software installers without making any permanent changes to your system.
2008-01-22
Polyglot Blog
Luis Diego Fallas is a programming polyglot who keeps a blog, Exploring Beautiful Languages.
MIT Open CourseWare
MIT has an excellent site with lecture notes and other material available on their Open CourseWare site.
2008-01-21
XSTM
XSTM is an open source library that implements software transactional memory.
Speaking of STM, Simon Peyton Jones has written a great paper about implementing STM in Haskell, Beautiful concurrency.
2008-01-18
XSLT Root Node Problem
I am stumped by what appears to be a bug in both the IE7 and Saxon6.5.5 - which leads to wonder if it is not a bug at all but rather my misunderstanding of the way things work. I tried to write a recursive XSLT template that worked its way up the element hierarchy, recursing until the node set '..' was empty. To my surprise, an endless recursion occurred. If I run Saxon in the debugger, I get the following expected results when the context has '.' bound to the top-most XML element:
local-name(.) -> test-checklist (my outermost element name)
local-name(*[1]) -> category (the element name of the first child element)
count(. | /) -> 2 (this node is not the root)
count(.. | /) -> 1 (the parent node is the root)
count(/..) -> 0 (the root has no parent)
However, if I then try <xsl:apply-templates select=".."/>
, '.'
is still bound to the document's outermost element (test-checklist in
this case).
I tried the Xalan and .NET 1.0 transformers as well. Everyone agrees - an endless loop occurs. I don't understand this, and I've scoured both the XSLT and XPath specifications to find an explanation (without success). As a workaround, I changed the termination test to 2 = count(.. | /).
Update: I found it. My template was matching '*'. '*' does not match '/'. Thus, once my code recursed up to the root, the default template rule for '*|/' kicked in. The default rule invokes apply-templates on the context node's children. Thus, execution would just rattle around on the top-most element. Subtle.
2008-01-17
2008-01-11
IE7 vs Line Breaks
In IE7 (and maybe other versions of IE), line breaks are represented as carriage returns (only). You will see this, for example, if you use DOM to extract text from a PRE element.
2008-01-09
Scala Partial Functions
In Scala, a block that contains a series of case expressions defines a partial function, thus:
val x: PartialFunction[Any,Int] = {case x: String => 1 case _: Any => 2}
Note that the type of x in the example must be specified because the input parameter to the partial function cannot be inferred. This would not be necessary in circumstances where there is enough information to infer the type, e.g.
def doit(f: PartialFunction[Any, Int]) = f("hi")
doit({case x: String => 1 case _: Any => 2})
SQL Server Query Analyzer vs 'GO'
Be aware that Query Analyzer (and presumably OSQL) takes any line consisting solely of the word 'GO' as a batch terminator -- even if that word appears within a block comment.
SQL Server System-Generated Names
On SQL Server, the following query will list all SQL elements that have system-generated names (e.g. indexes, constraints):
select tab.name "table", obj.type "type", obj.name "name"
from (
select null "type", null "name", null "tableId" where 1=0
union select 'index', name, id from sysindexes where name not like '_WA_SYS%'
union select 'primary key', name, parent_obj from sysobjects where xtype='PK'
union select 'foreign key', name, parent_obj from sysobjects where xtype='F'
union select 'check constraint', name, parent_obj from sysobjects where xtype='C'
union select 'unique constraint', name, parent_obj from sysobjects where xtype='UQ'
union select 'default constraint', name, parent_obj from sysobjects where xtype='D'
) obj
inner join sysobjects tab on (tab.id=obj.tableId)
where objectproperty(obj.tableId, 'isMsShipped')=0
and obj.name like '%\_\_%' escape '\'
order by tab.name, obj.type, obj.name
2008-01-08
Retrieving SQL Server Objects by Structure
Indexes
On SQL Server, the following SQL statement will determine the name of an index given its key columns:
select idx.name
from sysobjects tab
inner join sysindexes idx on (idx.id=tab.id and idx.name not like ''_WA_SYS%'')
where 0=(
select sum(1)-sum(case when col.name=need.name then 1 else 0 end)
from sysindexkeys ikey
inner join syscolumns col on (col.id=ikey.id and col.colid=ikey.colid and ikey.id=idx.id and ikey.indid=idx.indid)
full join (
select null keyno, null name where 1=2
union select 1, 'lineItemId'
union select 2, 'projectId'
) need on (need.keyno=ikey.keyno)
)
and tab.name='lineItem'
Note the cryptic _WA_SYS reference. SQL Server creates indexes that start with that prefix to support statistics operations. It can happen in practice that there are two indexes on the same column set: one user index plus one system index. We need to ignore the latter.
Primary Keys
In a similar vein, here is a statement to identify a primary key structurally (note that column order is not relevant):
select pk.name
from sysobjects tab
inner join sysobjects pk on (pk.parent_obj=tab.id and pk.xtype='PK')
where 0=(
select sum(1)-sum(case when col.name=need.name then 1 else 0 end)
from sysindexes idx
inner join sysindexkeys ikey on (ikey.id=idx.id and ikey.indid=idx.indid)
inner join syscolumns col on (ikey.id=col.id and col.colid=ikey.colid)
full join (
select null name where 1=2
union select 'chartId'
union select 'rowId'
union select 'chartIndex'
) need on (need.name=col.name)
where idx.name=pk.name
)
and tab.name='tbCustomChartDataSet'
Foreign Keys
To find a foreign key:
select fk.name
from sysobjects tab
inner join sysobjects fk on (fk.parent_obj=tab.id and fk.xtype='F')
where 0=(
select sum(1)-sum(case when col.name=need.name and rcol.name=need.rname then 1 else 0 end)
from sysforeignkeys con
inner join sysobjects rtab on (rtab.id=con.rkeyid)
inner join syscolumns col on (col.id=con.fkeyid and col.colid=con.fkey)
inner join syscolumns rcol on (rcol.id=con.rkeyid and rcol.colid=con.rkey)
full join (
select null name, null rname where 1=2
union select 'projectId', 'projectId'
union select 'projectStageId', 'projectStageId'
) need on (need.name=col.name and need.rname=rcol.name)
where con.constid=fk.id
and rtab.name='tbProjectStageXref'
)
and tab.name='lineItem'
Column Constraints
To find a column constraint of some type (a 'check' constraint in the example):
select def.name from sysobjects def
inner join sysobjects tab on (tab.id=def.parent_obj)
inner join sysconstraints con on (con.id=tab.id and constid=def.id)
inner join syscolumns col on (col.id=tab.id and col.colid=con.colid)
where def.xtype='C'
and tab.name='unitConvVolume'
and col.name='qty_2'
Unique Constraints
To find a column constraint of some type (a 'check' constraint in the example):
select idx.name
from sysobjects tab
inner join sysobjects con on (con.parent_obj=tab.id)
inner join sysindexes idx on (idx.name=con.name)
where 0=(
select sum(1)-sum(case when col.name=need.name then 1 else 0 end)
from sysindexkeys ikey
inner join syscolumns col on (col.id=ikey.id and col.colid=ikey.colid and ikey.id=idx.id and ikey.indid=idx.indid)
full join (
select null keyno, null name where 1=2
union select 1, 'budgetId'
union select 2, 'afeName'
) need on (need.keyno=ikey.keyno)
)
and tab.name='tbAfe'
Script Generation
Even more exciting, here is an SQL statement that generates an SQL script that can be run in another database to rename all indexes to match the names used in the first database (only indexes on user tables and that are not associated with a constraint or 'text' column are considered).
select text from (
select null tab, null idx, null seq, null text where 1=0
union select tab.name
, idx.name
, blk.seq
, replace(replace(blk.text, '$TABLE$', tab.name), '$INDEX$', idx.name) text
from sysindexes idx
inner join sysobjects tab on (tab.id=idx.id)
cross join (
select null seq, null text where 1=0
union select 1, 'declare @idx_name sysname'
union select 2, 'select @idx_name=tab.name+''.''+idx.name '
union select 3, 'from sysobjects tab '
union select 4, 'inner join sysindexes idx on (idx.id=tab.id and idx.name not like ''_WA_SYS%'') '
union select 5, 'where 0=( '
union select 6, ' select sum(1)-sum(case when col.name=need.name then 1 else 0 end) '
union select 7, ' from sysindexkeys ikey '
union select 8, ' inner join syscolumns col on (col.id=ikey.id and col.colid=ikey.colid and ikey.id=idx.id and ikey.indid=idx.indid) '
union select 9, ' full join ( '
union select 10, ' select null keyno, null name where 1=2 '
/* 1000-9999 reserved for key column names */
union select 10000, ' ) need on (need.keyno=ikey.keyno) '
union select 10001, ') '
union select 10002, 'and tab.name=''$TABLE$'' '
union select 10003, 'exec sp_rename @idx_name, ''$INDEX$'', ''INDEX'''
union select 10004, 'go'
union select 10005, ''
) blk
where tab.xtype='U'
and idx.indid<>255
and idx.name not like '_WA_SYS%'
and not exists (select 1 from sysobjects where name=idx.name)
union select tab.name
, idx.name
, 1000+ikey.keyno
, ' union select '+cast(ikey.keyno as varchar)+', '''+col.name+''''
from sysindexes idx
inner join sysobjects tab on (tab.id=idx.id)
inner join sysindexkeys ikey on (ikey.id=idx.id and ikey.indid=idx.indid)
inner join syscolumns col on (col.id=idx.id and col.colid=ikey.colid)
where tab.xtype='U'
and idx.indid<>255
and idx.name not like '_WA_SYS%'
and not exists (select 1 from sysobjects where name=idx.name)
) data
order by tab, idx, seq
2008-01-05
Mandelbrot in Mathematica
Just for laughs, a implemented a tiny Mandelbrot application in Mathematica.
mandelbrot =
Compile[{{cx, _Real}, {cy, _Real}, {limit, _Integer}},
Module[{count = 0, zx=cx, zy=cy, zx2=0, zy2=0, tx=0, ty=0},
While[count <= limit && (zx2 = zx^2)+(zy2 = zy^2) < 4,
++count;
tx = zx2 - zy2 + cx;
ty = 2 zx zy + cy;
zx = tx;
zy = ty
];
count
]
];
Manipulate[
ReliefPlot[
Table[
mandelbrot[x, y, limit],
{y, y0, y0 + x1 - x0, (x1 - x0) / resolution},
{x, x0, x1, (x1 - x0) / resolution}
],
ColorFunction -> colors
],
{limit, 50},
{resolution, 400},
{x0, -2},
{x1, 1},
{y0, -1.5},
{colors, Sort@ColorData["Gradients"]}
]
2008-01-04
Scala
Scala is a programming language that seems to be largely a fusion of Haskell and Java. As is the fad these days, it has its own web framework called lift. I spent some time working with Scala, and it appears to be a promising successor for Java. There is a growing, vocal community using it.
My attention was drawn back to Scala by Bruce Eckel's blog entry Java: Evolutionary Dead End. Quite a few people in the blogosphere share the view expressed in a blog entry by n8han, The awesomeness of Scala is implicit.
Blog Archive
-
▼
2008
(78)
-
►
Jan 2008
(18)
- Vital and Pivotal
- Implications of Non-Strict Functions
- Ivy
- Sandboxie
- Polyglot Blog
- MIT Open CourseWare
- XSTM
- XSLT Root Node Problem
- Prefuse
- IE7 vs Line Breaks
- Scala Partial Functions
- SQL Server Query Analyzer vs 'GO'
- SQL Server System-Generated Names
- Retrieving SQL Server Objects by Structure
- LISP Survey
- Mandelbrot in Mathematica
- Wicket
- Scala
-
►
Jan 2008
(18)