It Already Is A Scripting Language

It Already Is A Scripting Language

Rate This
  • Comments 51

My recent post about the possibility of considering maybe someday perhaps adding "top level" methods to C# in order to better enable "scripty" scenarios generated a surprising amount of immediate emphatic pushback. Check out the comments to see what I mean.

Two things immediately come to mind.

First off, the suggestion made by a significant number of the commenters is "instead of allowing top-level methods, strengthen the using directive." That is, if you said "using System.Math;" then all the static members of that class could be used without qualification.

Though that is a perfectly reasonable idea that is requested frequently, it does not actually address the problem that top-level methods solve. A better "using" makes things easier for the developer writing the call. The point of top-level methods for scripty scenarios is to make it easier on the developer writing the declaration. The point is to eliminate the "ritual" of declaring an unnecessary class solely to act as a container for code.

Second, and more generally, I am surprised by this pushback because of course C# already is a scripting language, and has had this feature for almost a decade. Does this code fragment look familiar?

<%@ Page Language="C#" %>   
<script runat="server">   
  void Page_Load(object sender, EventArgs e) 
  {
      // whatever
  }
</script>
...

Where's the class? Where are the using directives that allow "EventArgs" to be used without qualification? Where's the code that adds this method group to the event's delegate? All the ritual seems to have been eliminated somehow. That sure looks like a "top-level method" to me.

Of course we know that behind the scenes it isn't any such thing. ASP.NET does textual transformations on the page to generate a class file. And of course, we recommend that you use the "code behind" technique to make a file that actually contains the methods in the context of an explicit (partial) page class, to emphasize that yes, this is a class-based approach to server-side processing.

But you certainly do not have to use "code behind". If you're an ASP traditionalist (like me!) and would rather see C# as a "scripting language" that "scripts" the creation of content on a web server, you go right ahead. You can put your "top level" methods in "script" blocks and your "top level" statements in "<% %>" blocks and you'll thereby avoid the ritual of having to be explicit about the containers for those code elements. The ASP.NET code automatically reorganizes your "script" code into something that the C# compiler can deal with, adding all the boring boilerplate code that has to be there to keep the compiler happy.

But consider now the burden placed upon the developers of ASP.NET by the language design. Those guys cannot simply parse out the C# text and hand it to the C# compiler. They've got to have a solid understanding of what the legal code container topologies are, and jump through hoops -- not particularly difficult hoops, but hoops nevertheless -- to generate a class that can actually be compiled and executed.

This same burden is placed upon every developer who would like to expose the ability to add execution of end-user-supplied code to their application, whether that's in the form of adding extensibility via scripting, or by enabling evaluation of user-supplied expressions (such as queries). It's a burden placed on developers of productivity tools, like Jon Skeet's "snippet compiler", or LINQPad. It's a burden on developers who wish to experiment with REPL-like approaches to rapid development of prototypes, test cases, and so on.

I am not particularly excited about the convenience of the ability to save five characters by eliding the "Math." when trying to calculate a cosine. The exciting value props are that we might be able to lower the cost of building tools that extend the power of the C# language into third-party applications, and at the same time enable new ways to rapidly experiment and develop high-quality code.

Of course we do not want to wreck the existing value props of the language in doing so; as I said last time, we also believe that there is huge value in the language design naturally leading professional, large-scale application developers towards building well-factored component-based programs.

Like all design decisions, when we're faced with a number of competing, compelling, valuable and noncompossible ideas, we've got to find a workable compromise. We don't do that except by considering all the possibilites, which is what we're doing in this case.

  • (Too many comments for me to read this morning, so I may be duplication)

    If what you want from a script form of C# is simple, ad-hoc code, check out SharpScript (http://sharpscript.codeplex.com/). It's a fairly nice command-line script environment for .net languages. With a few alias statements and some simple helper classes you can do most of what you want from a scripting language right in C#, either in script files (a la VBS) or as arguments on the command line (a la perl -e).

    Their solution is to wrap what you give them inside the main() function of a command-line app, compile, and run. using directives are arguments (or part of your preferred environment) and prerequisite assemblies can be configured as needed.

    If what you want from a script language is write-only obscurity, lack of type checking, quick-and-dirty-hack-something-together-that-works-until-it-runs-in-production, use something else (for example, while perl can be beautiful, but it's more often used that way).

    Of course, these days I'd rather just use PowerShell for most of my scripting. I'm not sure what C# provides over PowerShell with C# extensions except to those people who want to use .net on non-Windows platforms (are there actually people doing that with production code, instead of just toys and samples? I wouldn't be surprised if there were, but i would be surprised if there were a lot of them).

  • Hello there Eric,

    Thanks for the transparency and the good post. I'm not sure I 100% understand all the comments and discussion, but as a C# developer I would definitely like some means of allowing global namespaces. Personally I would prefer something on the lines of upgrading the using directive, something like:

    using System.Web;

    using global System.Math;

    Which would allow me to write Abs(x); in my code .. this would be transparent and very helpful.

    I think top-level methods if enabled should:

    - be enabled through a compiler switch

    - be directly declared for a given code-block/cs file

    - have syntax for unambiguous calling of particular methods.

    But of course I defer to the opinions of all the hard-core experienced C# coders out there.. I'm happy with the way things are.

  • It seems to me that what would really add value to C# is not scripty global-level statemetns per se, but rather an easy-to-use mechanism for creating an isolated code execution context that can then be used to run user-entered script code.

    For example, say I've got a desktop application that I want to add scripting features to. What I'd really like to do is create a new execution context, specify what types and/or namespaces the code that executes in this context should have access to. maybe add references to some existing object instances, and then feed it a string to compile and execute within that context (maybe with some default using statements to absolutely minimize the amount of knowledge the script author needs).

    In a more complex scenario I might want to load multiple source files defining a bunch of classes into the same context so they can reference each other, or re-use the same context to execute a bunch of code snippets that manipulate the same data. But in each case the hard part of the problem is setting up that isolated execution context in a way that protects your app from rogue script code, and limits scripts to accessing only the types you want them to be able to use.

    Trying to create the same effect with AppDomains is an imperfect solution at best, requiring an application developer to write inordinate amounts of boilerplate plumbing code and even then giving only the most coarse-grained control over what the script can do. What's really needed here is compile-time checking of type references and some automated handling of the AppDomain instancing and cross-AppDomain communication issues.

  • Actually, I could care less how "scripty" C# is or not. While it would be nice to be able to prototype and test things in C# without having to pay the compile-link tax, I'll live without it.

  • I don't know much about top-level implementation, but I wanted to comment on who ever said they would like the C# langrage to accept "using System.Math" to make all members of said class local.  This would be an awful idea in my opinion as I spend a lot of time looking at other people's code.  If this was allowed, then someone reading code would have issues keeping track of what the code is doing.  Furthermore, I would think that this coding pattern would break suggested coding standards.  The ides should never be to make things so easy that a even a monkey cam write code.  Heck, that's why we have VB, right?  ;)

    - Rashad Rivera

     Omegus Prime, LLC

  • Quote: 'I am not particularly excited about the convenience of the ability to save five characters by eliding the "Math." ' End Quote.

    Me neither in such small example, but I would be a lot more excited about being able to bring a class with constants into scope, to be able to avoid lots of duplication.

    An example scenario can be found here ("How to “import” a static class in C# ?":

    http://stackoverflow.com/questions/1423809

    and I am now talking about the posting with SQL constants example, which would let you write this kind of code (if static imports a la Java would be possible):

               DBQuery.Select()

               .Field(CustomerID)

               .Count(OrderID)

               .From(Orders)

               .GroupBy(CustomerID)

               .OrderBy(CustomerID)

               .WhereField(OrderDate, Compare.GreaterThan, DBConst.DateTime(ordersAfter))    

    You certainly do not want to spread out hardcoded literals with names of SQL elements but they should be located in ONE place only, i.e. a class with constants, which can be reused from many other classes, and thus it should be located in a class of its own, but then you get the problem of having to duplicated the class name (or an alias) and a dot before every item from the constant class.

    /Peter

Page 4 of 4 (51 items) 1234