Arc Forumnew | comments | leaders | submit | kens's commentslogin
7 points by kens 6501 days ago | link | parent | on: Basic Graphics?

Here's one way to do graphics in Arc using DrScheme and MrEd.

I loaded "as.scm" into DrScheme.

I added simple make-canvas and draw-point commands to the as.scm code to use the MrEd Graphical Toolbox, and exported these commands to Arc.

I wrote a simple Arc function to draw the Sierpinski triangle using these graphics functions.

Specifically, I added the following code to as.scm.

  (define (make-canvas w h)
    (define frame (instantiate frame% ("Gasket by Ken Shirriff") (width w) (height h)))
    (define canvas (instantiate canvas% (frame)))
    (define dc (send canvas get-dc))
    (send frame show #t)
    dc ;; Return drawing context
    )
   
  ; Export simple drawing functions to Arc
  (xdef 'make-canvas (lambda (w h) (make-canvas w h)))
  (xdef 'draw-point (lambda (dc x y) (send dc draw-point x y)))
Then I clicked "Run" in DrScheme and entered the following into Arc:

  Arc>(def gasket (x y w)
        (if (< w 1)
            (draw-point dc x y)
            (do (gasket x y (/ w 2))
  	        (gasket (+ x (/ w 2)) y (/ w 2))
                (gasket x (+ y (/ w 2)) (/ w 2)))))
  Arc>(= dc (make-canvas 300 300))
  Arc>(gasket 0 0 256)
Supporting additional graphics functions is left as an exercise to the reader. For more information on MrEd, see: http://download.plt-scheme.org/doc/372/html/mred/mred-Z-H-39...

I would be interested in knowing if there is a way to access this library from Arc directly, without needing to hack as.scm.

-----

3 points by kens 6501 days ago | link | parent | on: Unimpressed.

I could use some help getting asv to run on Windows too. First I encountered the "The syntax of the command is incorrect" mkdir error, and used the fix from the http://jfkbits.blogspot.com/2008/01/digging-into-arc-in-24-m... blog post. Then I got the error open-output-file: cannot open output file: \"C:/tmp/shashCTtuJ1S8v7\", which I fixed by deleting "/tmp/" from the shash function in app.arc. Then the server started up but died a few seconds later with "srv thread took too long", same as in the 24 macros blog posting. I ran into this with both the original Arc download and the latest git repository version.

Does the web server run successfully on Windows, or should I stick to Linux? And if it runs on Windows, what's the secret?

-----

1 point by fredfred 6501 days ago | link

Impressed...by the walkthru on your link. I took the easy route for the failing mkdir and just created it from the command line.

I'm still confused how you're getting the server port open and I'm not. But then you don't seem to be having the problem with the shell out to the date command that I'm getting, so maybe you are running under cygwin?

-----

1 point by kens 6501 days ago | link

Yes, I'm using Cygwin. I still have no idea how to fix the 'srv thread took too long' problem, though.

-----

1 point by kens 6502 days ago | link | parent | on: Any way to write standalone scripts?

See http://arclanguage.com/item?id=1424

-----

2 points by kens 6502 days ago | link | parent | on: Can Arc run as a script instead of REPL?

Thank you! That's hugely helpful! I have to say, though, that 11 lines of boilerplate kind of obliterates Arc's conciseness advantage in the Arc Challenge :-)

-----

2 points by jfm3 6502 days ago | link

Not really, the Arc Challenge specifically discounts code for setting up libraries. All the script is doing is setting up libraries and loading your code.

-----


I think cookies vs closures is mixing apples and oranges. First, if you're using server-side state, the session ID can be stored in a hidden field (post) or URL (get) as Arc does, or the session ID can be stored in a cookie. The cookie behavior can be a bug or a feature depending on what you're doing; for example, you probably don't want two different tabs to have two different shopping carts and two sets of user information. Session ID in the URL has the disadvantages of ugly URLs ("sessionid=line noise"), lack of persistence, difficulty with bookmarking, and SEO negatives. Web frameworks (JSP, ASP) typically support either model.

Second, improving back button behavior is a matter of setting all the right nocache attributes. If you use forms, you're likely to have trouble with back navigation no matter what you do ("The page contains expired POST data").

Finally, I don't see how closures have any impact on the user experience one way or another, since it's just a different way of storing server-side state. The server can be implemented with closures, in-memory state, state backed by a database, or trained pigeons and it shouldn't make any difference to the user. (Modulo performance, reliability, etc of course.)

Am I missing something about how closures solve tabs and all other leaky abstraction issues?

-----

4 points by pc 6502 days ago | link

"I think cookies vs closures is mixing apples and oranges"

In theory, that's absolutely true; of course there's no technical reason that one can't use cookies and still keep the desirable properties of the Arc example (outlined in the grandparent).

But that's really the point: even though both styles make either model _possible_, they still encourage radically different approaches -- and this is of course borne out by the stuff people have submitted.

Secondly, on the perceived cookies/closures dichotomy, you reduce things to a question of where one should store the session ID, and that's a totally orthogonal issue.

We basically have three models -- sessions with IDs in cookies, sessions with IDs in URLs, and closures. Cookies give you a single, linear progression of state; session-IDs-in-URLs give you multiple linear progressions; and closures give you a nonlinear tree of progressions.

What do I mean here?

Sessions with IDs in cookies are simple: they're a single global state. Session IDs in the URL are a small bit closer to the closure-based approach, but they really just mean that the flow of state proceeds linearly in several independent threads. It's still a long way from matching the browser metaphor of "a page's state being contained within that page".

With session IDs in the URL, you can't get identical semantics to the closure-based approach unless you do make your sessions immutable, and create a new clone at each juncture. And if you do adopt this "session frame" approach (should that be "stack frame" approach?) you've basically created succumbed to some form of Greenspun's Tenth Rule.

Does this really matter? When state is contained within the page -- that is to say, when the closure-based approach is used -- it makes for much more flexible browsing. To take a tangible example, say you're searching for an airfare. You first search for tickets from SFO to BOS, then on the next page pick dates, and then on the third you (holding down alt) open a new tab investigating the price when you book first-class, while you proceed with economy in your main tab. You go through a few more pages, and you're now at the checkout in both. But you realise that you really need to go a day earlier, and that first-class is too expensive, so you close that tab, and hit back 'till your at the date selection page, and then head back to the checkout.

And it all just works. We humans are inquisitive creatures, and the tree of closures facilitates our natural instinct to poke and then retreat when things don't look right. Desktop app designers have long known this (even the first Macintosh had undo), and though generally far less information-dense, almost any modern desktop app supports virtually-infinite undo. Session-based approaches on the web choke this.

If the airline example sounds a bit contrived, it's because it is -- but at the same time, it's also a lot less chaotic than many people's flows when going through this an airline booking process (I know that for a fact because I spent a while investigating it once...).

The biggest difference between my example and real life is that, in mine, things _work_, whereas in real life, opening the new tab or using the back button would almost certainly completely screw the web-app up.

As heavy internet users, we've grown to accept this crap, because 1) we're used to it and 2) we know it's hard to get right. But it's not inevitable. Browsers can still be made to work as advertised.

This response has been hurried; I should probably make it into properly-written blog post or something.

-----

3 points by olavk 6501 days ago | link

Another option is to have all necessary information about the current operation in the URL. This is highly scalable, since you don't need to keep track of anything user-specific on the server(s), and the navigation supports branching and back/undo just like you describe.

Strangely enough PG specifically disallow this approach in his competition!

Most web apps need _both_ global session state and URL-based state. As others have pointed out, if you browse a product catalog, you would like to be able to branch into different browser windows or use the back-button. However, when you add an item to the shopping basket, you want it to be a global state change (you want have the same shopping basket in all windows), and you don't want a buy to be undone by clicking back.

Continuations are only an options for handling URL-based state, not for handling global state. And for page state they have some limitations.

For example, if all navigation is handled by continuations, you basically have to store a continuation for every hit indefinitely, since you dont know if the user have bookmarked the URL. If you don't want to store the continuations forever, you should only use them on pages that are not bookmarkable anyway, i.e. pages that are the response to form posts. But then the stated advantages, like the ability to branch and use the back button is moot, since you cannot do that anyway with form responses.

Continuations are really nifty for quick prototypes of web apps, but for production use, I believe they are a leaky abstraction.

-----

1 point by pc 6482 days ago | link

"Continuations are only an options for handling URL-based state"

This isn't true.

-----

6 points by emmett 6503 days ago | link

I think you're spot on. I just wanted to share a little trick, with regards to:

  Second, improving back button behavior is a matter of 
  setting all the right nocache attributes. If you use forms, 
  you're likely to have trouble with back navigation no matter 
  what you do ("The page contains expired POST data").
The key is to use a 302 redirect immediately after a successful post rather than a 200. This makes using the back button take you back to the form, rather than trying to POST it again.

On the other hand, I find the ability to resubmit forms with the back button very useful at times, so I'm not sure this is always the right thing to do. But it's a neat trick.

-----

1 point by JoshKingBoston 6502 days ago | link

Post/Redirect/Get (http://en.wikipedia.org/wiki/Post/Redirect/Get) is the relevant design pattern to handle this situation.

-----


Against my better judgement, here's a JSP solution:

  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <title>Contrived example</title></head><body><div>
  <% if (null == session.getAttribute("page")) {
        session.setAttribute("page", "1"); %>
        <form action="said.jsp" method="post">
        <div><label>Enter something <input type="text" name="foo"/>
        <input type="submit"/></label></div></form>
  <% } else if ("1".equals(session.getAttribute("page"))) {
        session.setAttribute("page", "2");
        session.setAttribute("value", request.getParameter("foo")); %>
        <a href="said.jsp">click here</a>
  <% } else if ("2".equals(session.getAttribute("page"))) {
        session.setAttribute("page", null); %>
        you said: <%= org.apache.commons.lang.StringEscapeUtils.escapeHtml((String)session.getAttribute("value")) %>
  <% } %>
  </div></body></html>
While it's not as concise as the Arc solution, it does have some advantages. First, it satisfies the requirement of returning the user's input, even for accented characters. Second, it doesn't pass stuff in the URL like the Arc solution. Third, it plugs the obvious XSS hole. Fourth, it produces valid HTML. (I picked XHTML for maximum pain :-)

-----

1 point by namaste 6504 days ago | link

Here's this same thing translated to Ruby + custom Web Framework + Tenjin (which does the escaping with the ${} command. #{} and it does not escape.)

  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <title>Contrived example</title></head><body><div>
  <?rb if not @w.session['page']
        @w.session['page'] = '1' ?>
        <form action="jsp_said" method="post">
        <div><label>Enter something <input type="text" name="foo"/>
        <input type="submit"/></label></div></form>
  <?rb elsif @w.session['page'] == '1'
        @w.session['page'] = '2'
        @w.session['value'] = @w.f('foo') ?>
        <a href="jsp_said">click here</a>
  <?rb elsif @w.session['page'] == '2'
        @w.session["page"] = nil ?>
        you said: ${@w.session['value']}
  <?rb end ?>
  </div></body></html>

-----