There are plenty of object-oriented programming languages in .NET such as C#, IronPython and IronRuby. Why would you want to use Cobra instead?
This would seem to be a silly question on first glance. However, Cobra is much more than Python without the eccentricities and with the raw performance of C#; In addition, It has the support for automated unit-testing from D, the software contracts introduced by Eiffel, the static and dynamic binding of Objective-C or Boo. It introduces Nil-tracking to eliminate some of the most difficult errors in code that are caused by NULLs being passed as parameters. Moreover, Cobra creates the same kinds of classes, interfaces, method signatures, etc. that are found in C# and Visual Basic, so that it will produce assemblies that are compatible. This allows Cobra to coexist with the more conventional .NET languages in applications.
Cobra isn’t a port to .NET from the world of Linux, it is intrinsically bound up in the .NET framework and takes advantage of the standard library, the class/object model, including events, and the use of generics. Rather than compiling straight to MSIL, it acts as a pre-processor for C# which is in turn compiled to MSIL. This means that it is safe to use in a mixed project that uses C# as well as Cobra. It plays nice with C# and VB
Cobra is an excellent general-purpose imperative scripting language as it is able to do dynamic binding.
An aim of Cobra is to allow the programmer to write robust applications with a minimum of bugs. The use of Contracts, which are analogous to constraints in SQL, are implemented in a way that is very close to Eiffel. Cobra also allows you to embed unit-tests into the code, which can be executed at compile time, and every time the code is run, to catch the simple but irritating coding errors without having to create a separate test suite. You can use both of these, but they definitely improve the readability of code, since the unit tests also act as coding examples. If you also add the ‘documentation’ feature, primitive though it is, your source code will be starting to look clear and nicely laid out. Cobra actually rewards good coding practices.
What impressed me most about Cobra was its simplicity. It is very simple to take C# source and convert it to Cobra, mostly by deleting various brackets and semicolons, and tidying things up; Converting old Python code is even easier. one can even take pseudo-code and convert it into Cobra without breaking into a sweat. This is a computer language written for the benefit of humans rather than machines.
I therefore put Cobra to the acid test. Can one make practical use of it where one would otherwise be forced into using PowerShell? Would it make a good UnPowerShell?
How about interacting with SQL Server by executing a stored procedure? I spat on my palms, and an hour later I had this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
@ref 'System.Data' @ref 'System.Data.SqlClient' use System.Data use System.Data.SqlClient class Program """ this executes the stored procedure 'dbo.uspGetBillOfMaterials' in a copy of Adventureworks on a server you specify in the command line and snds the results as output in a comma-delimited stream """ var columns =1 var line="" def main try using conn = SqlClient.SqlConnection("Server=[CobraCore.commandLineArgs[1]];DataBase=AdventureWorks;integrated security=SSPI") conn.open cmd = SqlClient.SqlCommand("dbo.uspGetBillOfMaterials", conn) cmd.commandType = CommandType.StoredProcedure cmd.parameters.add("@StartProductID",SqlDbType.Int) cmd.parameters['@StartProductID'].direction = ParameterDirection.Input cmd.parameters['@StartProductID'].value='800' #The @DateOfEntry Output parameter cmd.parameters.add("@CheckDate",SqlDbType.DateTime) cmd.parameters["@CheckDate"].direction = ParameterDirection.Input cmd.parameters['@CheckDate'].value='1 Jan 2003' using rdr = cmd.executeReader #because we are getting a result back .columns=rdr.fieldCount while rdr.read .line="" for i in .columns .line += ","+"[rdr.getValue(i)]" print "[.line[2:]]" catch err as SqlException #Catch Exceptions for i in err.errors.count print err.errors[i] catch print "Could not execute procedure on server [CobraCore.commandLineArgs[1]]" |
You can see that this is pretty close to C#, but with less typing. This looks like C# mainly because I’m not using asserts, unit tests, and software contracts. I’m still clutching the handrail rather than going off the deep-end. Whilst developing this application, I was struck by the helpfulness of the compiler. It seemed to want you to succeed. Even more of a surprise was the quality of the help on the Cobra Programming Language site. there is a search function that generally seems to find something useful, and several ‘How to’ examples and more complete samples. I was planning to give you an introduction to Cobra as part of this review, but the quality of what is written on the Cobra-Language.com site, and of Chuck Esterbrook’s interview with Richard Morris on his election to Simple-Talk’s ‘Geek of the Week’ makes it unnecessary. Please read those instead.
OK. How about doing something a bit cleverer than the first example, and using SMO to list out the properties of all the databases on a server? I apologise for the database slant, but I’m interested in settling on a language that will allow me to script out all the Database Administration chores that I never seem to find the time to do properly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
@ref 'C:\Program Files\Microsoft SQL Server\90\SDK\Assemblies\Microsoft.SqlServer.Smo.dll' @ref 'C:\Program Files\Microsoft SQL Server\90\SDK\Assemblies\Microsoft.SqlServer.SmoEnum.dll' @ref 'C:\Program Files\Microsoft SQL Server\90\SDK\Assemblies\Microsoft.SqlServer.SqlEnum.dll' @ref 'C:\Program Files\Microsoft SQL Server\90\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll' use Microsoft.SqlServer.Management.Smo class Program def main """ Use SMO to type out the database properties for every database on the server """ try server as Server = Server(CobraCore.commandLineArgs[1]) dbs as DatabaseCollection? = server.databases #get the databases for db as Database in dbs #for each database print db.name for prop as Property in db.properties #for each database print +' [prop.name]:=[prop.value]' server.connectionContext.disconnect #disconnect from server catch smoError as SmoException #Catch SMO Exceptions print "[smoError.smoExceptionType] [smoError.message]" catch print "Could not fetch the properties of [CobraCore.commandLineArgs[1]]" print err.errors[i] catch print "Could not execute procedure on server [CobraCore.commandLineArgs[1]]" |
To run this, you’ll have to supply the name of the server in the command line. You can do this via the compiler, which can be persuaded to compile and run in one go. You may need to change the references to the SMO assemblies. (I have used the SQL Server 2005 versions).
Having got SMO to work with Cobra, then there need be no stopping. Here is a simple script to write out the entire build script for a database to a file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
@ref 'C:\Program Files\Microsoft SQL Server\90\SDK\Assemblies\Microsoft.SqlServer.Smo.dll' @ref 'C:\Program Files\Microsoft SQL Server\90\SDK\Assemblies\Microsoft.SqlServer.SmoEnum.dll' @ref 'C:\Program Files\Microsoft SQL Server\90\SDK\Assemblies\Microsoft.SqlServer.SqlEnum.dll' @ref 'C:\Program Files\Microsoft SQL Server\90\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll' use System.Collections.Generic use Microsoft.SqlServer.Management.Smo class Program def main """ Use SMO to write out a complete build script for a database syntax: ScriptDatabase <Server> <Database> <FileAndPath> """ try server as Server = Server(CobraCore.commandLineArgs[1]) db as Database? = server.databases[CobraCore.commandLineArgs[2]] script as Transfer = Transfer(db) script.copyAllObjects = true script.copySchema=true sc=script.scriptTransfer list = List<of String>(sc.count) for line as String in sc list.add(line) File.writeAllLines(CobraCore.commandLineArgs[3], list.toArray) server.connectionContext.disconnect #disconnect from server catch smoError as SmoException #Catch SMO Exceptions print "[smoError.smoExceptionType] [smoError.message]" catch print "Could not script out the database[CobraCore.commandLineArgs[2]]" |
One could go on with a number of examples, but the sample code in the Cobra website is difficult to improve upon.
If you are completely wedded to Visual Studio, then you are in for a shock. Although integration is going to be possible once the compiler is able to produce XMLdocs, it isn’t there yet. Chuck is working on it but it isn’t there yet. This doesn’t worry me since I use Editpad Pro. I didn’t even need a new syntax colorizing scheme since the Python one worked well enough. It took me ten minutes to fix it all up. The compiler is very easy to use and has been crafted to make it usable for quick scripting. It is lightning-fast too. In fact, the development process can be speeded up so much by using a programmers editor instead of an all-things-to-all-programmers IDE that it is rather exhilarating.
So what were my first impressions of Cobra? The very fact that I’m torn between F# and Cobra is an indication of Cobra’s quality. After trying out some of the samples and modifying them, and then going ahead and cutting a couple of useful routines from scratch, I feel confident enough to progress with it. For me, the ‘scriptability’ and extra test features give it an edge over C# for the uses I have for it. There are things that would improve Cobra: Visual Studio support would be great, and an interactive console and DLR would probably tip the balance even further. I have to admit that I have a closer cultural affinity to Cobra than PowerShell or F#, so I think I’ll continue to use it for scripting administrative jobs. Because the support by Microsoft for PowerShell is at such a fundamental level, with the provision of applets for specialised work, I’m not going to be able to avoid PowerShell entirely, but it is nice to think that, for most scripting purposes, there’s a viable alternative.
Note: The developer of Cobra, Chuck Esterbrook, gives more details of the language and the thinking behind it here on Simple-Talk in interview with Richard Morris in Chuck Esterbrook: Geek of the Week
Load comments