We just keep oscillating back and forth between thin clients and chubby clients. We started with basic terminals receiving text from the server and displaying it, then added control codes and more smarts until we got into things like VT102 and beyond. We pushed all the User Interface over to the client for rendering.
Now that the Web is squarely here to stay, we've got islands of activeness in the form of browser plugins like Flash and Silverlight, some of which are cross platform and some less-so, but for now my quad-processor machine spends a lot of time either:
There's a thousand different ways to generate your UIs and send them down to the browser/client for rendering. Turns out there are as many ways as there are languages. If you've got a programming language, there's a web framework for it.
I don't know why this surprises me. Folks love their programming language, whatever it is, and it makes sense that the "ultimate" proof of their language's awesomeness would be the "ultimate web framework."
That said, it still seems funny to me that the greatest (er, most overtly visible) example of a language's superiority is how well it works as a Web Framework angle-bracket generator.
For example, Arc is Paul Graham's new LISP dialect that a number of people are talking about (with varying degrees of enthusiasm). A tutorial on Arc is available here and there's an "Arc Challenge" being discussed here as folks try to this slightly more complex Hello World example:
"First generate a page with an input field and a submit button. If the user clicks on submit, he gets a second page with a link saying "click here." If he clicks on that, he gets a third page saying "you said: ..." where ... was whatever he put in the input field. This has to happen without the value being passed in the url; it should not be possible to change the behavior of the third page by editing the url in the second."
In Arc/LISP it looks like this:
(defop said req (aform [w/link (pr "you said: " (arg _ "foo")) (pr "click here")] (input "foo") (submit)))
It's pretty terse to look at if you're used to doing things in more conventional languages. There's a lot of fun solutions like this entirely client-side one in JQuery:
$('body').append('<input id = "myInput" /><input type = "submit" />') .find('input[@type=submit]').click(function() { val = $('#myInput').val(); $('body').html('<a href = '#'>click here</a>').find('a').click(function() { $('body').html('You said: ' + val); }); });
Other examples include:
#!/usr/bin/env ruby require "ramaze" class MainController < Ramaze::Controller def index if f = session['foo'] then "you said #{f}" elsif session['foo'] = request['foo'] then A("click Here", :href => '/') else '<form><input name="foo" /><input type="submit"></form>' end end end Ramaze.start :port => 7001 __END__
Then Rails:
def said if request.method == :post session[:said] = params[:said] render :action => "clickhere" else render :action => "result" if session[:said] end end default template said.rhtml: <% form_tag do %><%= text_field_tag "said", "" %><%= submit_tag %><% end %> clickhere.rhtml: <%= link_to "click here", "" %> result.rhtml: You said <%= session[:said] %>
| something | something := self request: 'Say something'. self inform: 'Click here'. self inform: something
serveAs "said" $ hasIndex $ \x -> "click me" `linksTo` (text ("You said " ++ x))
<%@ Page Language="C#" ClassName="WebApplication1._Default" %> <script runat="server"> // C# and ASP.NET protected void SubmitButton_Click(object sender, EventArgs e) { MultiView1.ActiveViewIndex = 1; } protected void ClickHereButton_Click(object sender, EventArgs e) { SaidLabel.Text = string.Concat("You said: ", SayTextBox.Text); MultiView1.ActiveViewIndex = 2; } </script> <html> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0"> <asp:View runat="server"> <asp:TextBox ID="SayTextBox" runat="server" /> <asp:Button ID="SubmitButton" runat="server" Text="Submit" OnClick="SubmitButton_Click" /> </asp:View> <asp:View runat="server"> <asp:LinkButton ID="ClickHereButton" runat="server" Text="Click Here" OnClick="ClickHereButton_Click" /> </asp:View> <asp:View runat="server"> <asp:Label ID="SaidLabel" runat="server" /> </asp:View> </asp:MultiView> </form> </body> </html>
Shorter but not-typical ASP.NET:
Shorter but non-idiomatic C#/ASP.NET: <%@ Page Language="C#" %> <html> <head> <title>Said</title> </head> <body> <form id="form" runat="server"> <% if (!IsPostBack) { %> <input name="foo" /> <input type="submit" /> <% } else if (Request.Form["foo"] != null) { Session["foo"] = Request.Form["foo"]; %> <a href="javascript:form.submit()">click here</a> <% } else { %> you said: <%=Session["foo"]%> <% } %> </form> </body> </html>
There are so many ways to generate the same result. Big thanks to Ted Glaza for his indirect help on this post.
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.
Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.