Sanity Checking for Scripting Languages
My little goofball mistake with Rails reminded me of one of the biggest timesinks in working with scripting languages: there's no compiler doing sanity checking for you.I'd say approximately 90% of the issues I've debugged over the course of nine years of using PHP, for example, are due to a mistyped variable which I think is the same as another variable. I just did the same with with Ruby. In a compiled language, you hit errors (or at least warnings) like this upfront.
What I would personally like is something that will run through my Ruby or PHP code and tell me things like "Ummm, Mr. Stevenson, you seem to have a variable here doing absolutely nothing. Is that really what you want?"
Anybody else think there's value in this? Does anything like this already exist for Ruby? Am I just passing the buck?

Sanity Checking for Scripting Languages
Posted Dec 24, 2006 — 20 comments below
Posted Dec 24, 2006 — 20 comments below
Mike Abdullah — Dec 24, 06 2847
Sometimes with AppleScript things would just fail and I had absolutely no idea - usually it was simply down to a mistyped function name or suchlike.
Cameron Hayne — Dec 24, 06 2848
use strict;
use warnings;
Maybe there is something similar for Ruby or PHP?
Matt Tavares — Dec 24, 06 2849
perhaps?
Matt Tavares — Dec 24, 06 2850
http://php.net/error_reporting
Chuck — Dec 24, 06 2854
Ruby does have some error checking, but due to the lack of a compile time, they're not automatically run for you in the process of making the program. In your particular case, the error Ruby gave was about as good as any you'd get in a C compile-time check: "No such method or variable: 'photo'".
Scott Stevenson — Dec 24, 06 2855
Objective-C does most of the stuff you mention, even though it's a compiled language. You can have it both ways (or pretty close). I'm not looking for it to find every single problem, just the obvious typos and whatnot.
Ruby gave was about as good as any you'd get in a C compile-time check: "No such method or variable: 'photo'"
Well, sort of. The error mentions "ActiveRecord::ConnectionAdapters::MysqlAdapter," which doesn't tell me a lot about where to look. If it mentioned the file in question (maybe it can't), that would be helpful. Maybe a trace would have helped.
Scott Guelich — Dec 24, 06 2856
I've become more and more interested in Ruby, but one of the hardest things to give up from the Perl world is this kind of basic sanity checking, which really isn't hard for a script interpreter to provide.
Another Ruby custom I've had a hard time getting used to is omitting parentheses when calling methods without arguments. In most languages parens are required for argument-less methods/functions, and with Perl you have the leading punctuation to differentiate variables from functions, but in Ruby you can't tell by looking whether "photos" is a variable or a method. In your case the interpreter guessed wrong -- which only made the error more cryptic.
Chuck — Dec 24, 06 2857
Ah, you're right. I think that's actually the fault of Rails catching the error and creating its own message. The standard error Ruby gives in that case is along the lines of [name of file]:[line number]: undefined local variable or method `[whatever]' for [the object it was called on][/i]. I'm not sure why ActiveRecord overrides that.
dc — Dec 24, 06 2858
Maybe that's not what you're looking for, though. You can't write a unit test to make sure you're using the correct block-level variables, as in the specific problem you had. But having reasonably comprehensive unit tests at least makes sure that all your code gets executed. At that point, the interpreter error messages ought to be as good as compiler errors, once you get used to the bugs you're apt to introduce in whatever language you're writing in (undefined method warnings being the Ruby indication that you probably mistyped something).
Patrick Thomson — Dec 24, 06 2859
Additionally, Python 2.4's new decorator syntax allows for some really neat decorators that automatically check the types of arguments passed into any given function. Decorators took me a little while to grok, but I think I understand them now - and boy, are they awesome.
Ruby, on the other hand, is a tad bit more difficult to enforce type safety - I'm not sure if Kwala does it, and many people say that there's no substitute for unit tests to ensure type safety. This problem has me quite inspired now - I may take a look at it.
David — Dec 24, 06 2860
For example: creating classes for OOP in Lua. Dangerous to do on larger scales because your text editor of choice won't show you "member functions" within your "classes". Which means you spend half of your days doing text searches for your functions, meaning that OOP actually becomes a productivity killer.
(BTW, Lua developers, check out SubEthaEdit for its highly useful Lua module.)
If you're creating more than a handful of functions in a scripting language, I think it's essential to start building a library of debugging routines, assertions and the like, including logging out the state of globals, printing out the stack calling chain, etc.
Also required is an extremely strict adherence to a naming system, regardless of the length of your variable/function/class names. Your scripting system generally won't care that your new variable "fooo" doesn't exist (it's a nil) and you probably won't pick it up until one of your Asserts find it.
Scripters may want to read Code Complete, especially the chapters on naming and project organization. It's even more relevant to scripts than it is for traditional, lower level languages.
Another trick is to use wrappers when loading scripts. Instead of calling the language's native load function, instead call your own wrapper which can remember details about the file (path, caller, etc.) and then attempt to load the file with error checking. If anything goes wrong, the trace can be logged to file.
When your application exits, files can also be checked off through this system to see if they've been cleaned-up properly or not. (Resource management is notoriously tricky in some scripting languages.)
Which brings me to the next trick: separate your code in to far more files than you would normally do in a compiled language. Why? Because it only takes one tiny mistake to screw up an entire script so by parcelling out your code into smaller sub-sections, you automatically help pin-point which file the problem belongs to. Then put all the sub-files into one folder for organizational purposes, where the folder is treated as a module or a unit.
Scripting languages are clearly the way of the future and are being used to extend applications in all manner of ways, but we need the tools to catch up. But that's supply/demand, so...
Finally, how to spend a day debugging in Lua:
local table = {};
That's it. No "keyword" warning error, no indication whatsoever that anything has gone wrong or that you've actually killed off a major package in the language. Heh.
labrat — Dec 24, 06 2861
This and the other so-called "goofball" post was a sigh of relief for me. Getting the hang of rails sometimes makes me feel like a total and complete idiot. I'm sure there are long-term productivity gains hidden somewhere but sometimes you waste large chunks of time going down undocumented rabbit holes so much that yu lose motivation.
Thanks for sharing this.
Chuck,
Anytime I see "ActiveRecord::ConnectionAdapters::MysqlAdapter", I usually assume that my MySQL server is stopped or something fudged my mysql gem.
Other than that I get debugging help from unit tests and taking a good look at the error messages that come up in the terminal (these can be quite informative when you get used to it).
ssp — Dec 24, 06 2863
(In a way this may be a milder version of the problems we are seeing with HTML: Browsers are expected to render incorrect code - thus making real-world browser programming a nightmare. Just compare this to the world of TeX where documents are properly compiled, error messages are given and documents render consistently over decades.)
Chris — Dec 25, 06 2867
Let me cite Don Roberts:
Static types give me the same feeling of safety as the announcement that my seat cushion can be used as a floatation device
Scott Stevenson — Dec 25, 06 2868
I do?
Jan — Dec 26, 06 2880
Did you ever had a look at PHP on Trax? I wanted to get what Rails was all about but I just didn't have the time to learn Ruby first. With a huge PHP background, Trax gives you a lot of Rails goodies without taking you too far away from what you know on a pretty intimate level.
PHP on Trax is not as complete and actively developed as Rails, but all the neat things are there and it is very easy to add features. There are more Rails-like implementations in PHP which I didn't look into yet.
I managed to bring up a project in around half the time it used to take with Trax. I even bought the Rails Book and I really appreciate the effort that is put into it but as for now, I can't afford to leave PHP for Ruby for my commercial work.
Currently, I try to wrap my head around ObjC and Cocoa and Carbon on the side, which is why I don't want to mess with Ruby now — maybe later.
Scott Stevenson — Dec 26, 06 2881
I actually like Ruby, and I'm happy to have an excuse to learn it. It's a spiritual brother of Objective-C in many ways. I do appreciate the heads up about PHP on Trax, though. I think a friend of mine will find this useful.
Currently, I try to wrap my head around ObjC and Cocoa and Carbon on the side, which is why I don't want to mess with Ruby now
Other than some syntax things, Rails makes a tremendous amount of sense to a Cocoa programmer (in my opinion). A lot of the dynamic language tricks Rails uses to make things work show up in similar ways in Cocoa.
Jan — Dec 26, 06 2885
--
no em-dashes? :-/
David — Dec 26, 06 2888
It can do, yes, which is why organization is of paramount importance. But you're missing out on truly enormous productivity gains by dismissing scripting languages.
Structured and written properly (with all the aforementioned naming and organizational tactics), you can typically write solutions within a scripting language within a fraction of the time that it takes for the same ObjC/C++ write-compile-test sequence (which of course, is done all day long in major projects). One reason for this is that scripts allow you to solve problems in fundamentally different ways than most compiled languages allow for.
Of huge importance: you can write and edit your scripts as your host application is running! So you can implement functionality without a compile, and see the results in real-time, without having to quit and relaunch the application. (Thus, state is retained and current logging remains intact.) For big projects, this can save hours in every single day. This can bring about certain emergent sorts of behavior and interesting features to your designs that would be next-to-impossible to see with traditional languages. Also, you can implement new functionality in a more human-like, buzzword-compliant language that doesn't care if you cast to void* or not.
Scott Stevenson — Dec 26, 06 2890
I think there's something to this, but there's a weird paradox here. You can write code at a higher level in a scripting language and let the interpreter work things out. In theory, this saves a lot of time. But the flexibility also means you can spend hours tracking down an errant comma (I have).
Maybe the best of both worlds is something that does a file-by-file syntax check for you without requiring you to deal with low-level data structures. I don't need my web app to actually be compiled, I just want something to check for what a compiler would check for.