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.

  • To take another view on this...

    C# could use a REPL interface.  REPL interactivity must support, at minimum, statements (though I'll admit that methods & classes would also be useful).

    From this perspective, we already have "top-level" methods: anonymous delegates. :-)

    Anonymous delegates are statements, and thus can be entered within a REPL wherever a statement is permitted (i.e. ~everywhere).

    Of course, the downside is that the syntax to declare a "method" is different, but the call-site is the same...

  • For me, the concerns of a top-level declaration are the abuses of a "global" namespace. I think that if the compiler treated the file as a class (i.e. when compiling it wrapped the file contents in a class if there were globally defined methods or variables), then this would mitigate that issue and allow for both implicit and explicit cross-file method references by using the filename like a classname. Of course, that brings other issues such as file names containing illegal characters.

  • @Jeff,

    I guess you are suggesting file scope for top-level functions and variables (they aren't really methods and fields any more), such that they aren't visible outside the file?  That sounds like a good solution to the problem of pollution in the global namespace and fears of action-at-a-distance.  C++ offers this via the nameless namespace.

    But you wouldn't simply wrap the entire file content in a class, you'd want type definitions to still be visible outside the file.  Note that including this anonymous static class in the lookup order for unqualified names without containment or inheritance is perfectly alright, the name resolution rules are part of the language/compiler, not the .NET runtime.

  • I would prefer if you had a toolkit that made it cheaper and easier to build tools and REPL interfaces, but under the hood it still doesn't allow global abuse. Think globally, act locally!

  • I agree with Matthew. If you do make it possible to introduce top-level functions, I'd suggest making them internal only; having no public top-level functions would also solve the pollution problem.

  • "It Already Is A Scripting Language" - by various technical criteria, sure. You, however, used the term "scripty" regarding programming languages which I think captures what you meant well.

    So while C# may be a scripting language because it meets various technical criteria, that technical criteria doesn't mean the language itself is "scripty". Programming in C# certainly doesn't feel like working in VBScript or JavaScript or any of the zillions of scripty/functional languages out there. It doesn't lend itself to super rapid development, and there is nothing wrong with that.

    So even though it already is a scripting language, from the comments it seems clear most developers using C# don't want to have it feel like a "scripty" language.

    Speaking as someone with years of experience in ASP.Net, under no circumstances would you embed C# "script" in the page for anything substantial anyway. It's not about emphasizing a class based approach; it's about creating something that can be maintained and enhanced because it was constructed in an organized manner, out of many smaller components.

    Global functions are pretty hard to build reusable components out of. Not to mention even with top level functions in ASP.Net it still needs custom syntax / custom implementation to import namespaces / implement interfaces / hook up the event handler to the event / etc.

    Adding execution of user supplied code to applications is trivial (thanks to you guys, of course!) -  Heck, you can always just generate the code yourself and compile it at runtime (http://msdn.microsoft.com/en-us/library/ms973253.aspx#automationmodel_topic11). If you want to add really good support for user extensibility, you need a lot more features than just a scripting ability anyway.

    So what exactly are you making easier? The 1% of the overall task?

  • Why not concentrate on improving the interoperability between C# and the existing scripting languages, rather than making it more "scripty", or "scriptical", or "scriptified", than it already is?

    Just a couple of weeks ago we were chewing rocks with frustration on our next ASP.net/SharePoint project, trying to implement a tree view that reflects a SharePoint list with folder structure AND does not jump back to the top node after the post-back, when the user selects something in it (we HAD to handle the SelectedNodeChanged event on the server side, hence the post-back).

    With better interaction between JavaScript on the client side and C# on the server side - by being able to directly refer the C# objects in JavaScript and JavaScript functions in C# - it would be A LOT easier to tame that SharePoint beast (and no, I have not forgotten ICallbackEventHandler: it didn't work too well, either, in that case; and using Something.Attributes["attribute"] = "value" does not look very intuitive to me).

    The dynamic type from C# 4 solves most of these problems on the server side; how about being able to control, on the client side, whether or not a server-side event handler should be called, and if yes, then with what parameters? How about better control over the post-backs, so that only the controls that have been changed are re-rendered, and only enough to reflect the change, rather than re-rendering the whole thing?

    Some would say, just use Silverlight/WPF, and I would agree, but not our Government client who only just (!!!) switched to Win XP SP 2 for their workstations. And the customer is always right, isn't he? :-)

  • There are other programming languages that already have the properties you desire from C#.

  • The 'scriptyness' of F# is one of its major selling points for me. I even find myself using F# to test out future C# algorithms, or even bits of the .Net framework - so much easier than creating a solution/project/gumpf, just for two lines of code.

  • +1 for doing..

    It is the one thing that I would most like to be more compatible with Python and F#!

  • <script runat="server"> is not a good design anyway, my understanding is that it exists for compatibility with classic ASP?

    Now <%= %> and <%# %> expressions are another matter, but they demonstrate that theoretically speaking top-level methods would not be enough -- top level expressions/statements are more like what is required (this is true for LINQPad as well).

    While it is probably possible to support these on compiler level, just providing a managed library to compile such code would be more than enough (and that library internally may use class wrapping/method wrapping, or somewhat else entirely). In this case, you would have a solution for LINQPad/ASP.NET (do snippet compilation with new library is you want globals, but use standard compiler for classic development).

  • have a look to the mono guys at http://tirania.org/blog/archive/2008/Sep-08.html

    they implemented a REPL almost a year ago

  • Great response Eric.  Fundamental changes like this tend to worry me, even if they're only proposed! lol.  It's great to see these things being discussed and it's also reassuring to see how they are regarded by you guys at Microsoft.

    +1 respect to your blog (I'd click the upvote button but this isn't SO).

    Very good point about the ASP.Net scripting by the way!

  • Eric,

    Your point is valid, but leaves out what I believe to be one important fact. The ASP.NET features you posted do not exist (except possibly as literals) in a .cs file!

    As soon as one sees an .aspx or .asmx they are aware that they are dealing with a different syntactical domain.

  • The fact that ASP.NET allows you to declare a method without a class does NOT make C# a scripting language. The defining features of a scripting language is not top-level methods, its top-level statements (PLEASE tell me you are not considering adding top level statements).

    No, the defining feature of a scripting language is that it can be used to extend existing applications by programmatically controlling the functionality exposed by those applications.

    But that said, of course we are considering the consequences of adding "top level" statements. You want to be in a REPL environment and have to have every statement you type in be in a method? That would be silly.

    Now, supposing we do make more things top-level, how to package it? Whether this syntax makes it in to the mainline language, or whether we expose a special "repl/script mode" on the compiler service that changes the allowable syntax to be more accepting, while keeping the mainline language the same, is a question about how the functionality is packaged

    Frankly, that does not interest me very much; I am more interested in how the semantic analysis of the language changes if the functionality exists at all. If it exists at all, someone has to design all possible interactions of new "top level" entities with the existing ones, and that's a potentially hard problem. Changing the packaging is easy; we already have lots of logic in the parser to allow or disallow parsing of certain features depending on switches. -- Eric

    Regardless, anyone who has done any significant ASP.NET development understands that the ASP.NET inline model is exactly the reason why we don't want that model spreading to the rest of the language: it is extremely difficult to maintain and does not lend itself toward good design.

    Again, I think the C# team needs to stop thinking of itself as the only player in the field. There are several good scripting languages on the .NET platform already, and I imagine more will emerge. C# should stay focused on what it was designed for: component-oriented application development.

    You think that we think of ourselves as the only player? We just spent a year adding features that let us more easily interoperate with Python. Is that the action of a team that considers itself the only player? We are well aware that the .NET platform is a multi-language platform; we spend a lot of our time trying to make it easier for C# to interoperate seamlessly with many other players in this space. We love that there are lots of players in this playground because ultimately we are about making the platform more attractive to all developers. -- Eric

Page 1 of 4 (51 items) 1234