Arc Forumnew | comments | leaders | submitlogin
1 point by akkartik 3 hours ago | link | parent | on: Variables & scoping complaint

I'm not following the two of you on precisely what this anti-feature is. Assigning to local variables using '=' does not create new global variables. Can you share a code sample showing what you're talking about?

It was originally used for powering Hacker News. Haven’t heard of it being used for much else.
2 points by krapp 17 hours ago | link | parent | on: Variables & scoping complaint

>So you could have lib#1 set var 'x' only for it to get clobbered by lib#2's version of var 'x' and arc just ignores this. That's bad. Really bad.

And how often is it intended behavior? How often does one want to have a macro parameter or apparently "local" variable overwrite an existing symbol globally and arbitrarily?

I can see it being useful in the case of "hot patching" code to just redefine a function, but that's still kind of crazy, since now the source code and running code are no longer the same. Might as well just edit the file and reload it, and have one source of truth.

It seems like an anti-feature. Something that seemed like a good idea in theory, but which in practice does more harm than good.

3 points by i4cu 1 day ago | link | parent | on: Variables & scoping complaint

This definitely not great, but having to use 'with' is not the real issue for me. In fact if you read through the code you'll notice that this style is often used deliberately (i.e. some people might argue that it's a feature).

I think the bigger issue is that global vars can be used without any errors or conflict warnings. So someone else can create code which sets globals which then gets loaded via libs and will pollute your program. So you could have lib#1 set var 'x' only for it to get clobbered by lib#2's version of var 'x' and arc just ignores this. That's bad. Really bad.

3 points by krapp 1 day ago | link | parent | on: Variables & scoping complaint

Yeah, as a newcomer I can attest that I did not know that. V here being global is really counter-intuitive:

  (defun f ()
     (= v 10)
I would have expected (and would prefer) the default to be to bind to whatever the current scope is, and to have global (file level, then application level) scope be opt-in rather than opt-out. We can't assume that it's more likely new users will be familiar with lisp idioms.
3 points by rocketnia 1 day ago | link | parent | on: Variables & scoping complaint

It looks like the particular solution you'd like is for `=` to act as it does in Python, but I think Arc's behavior is preferable to Python's.

For a variable to "default" to "global scope" is basically the definition of how lexical scope works. To find a variable's binding occurrence, you look outward until you find it. Once you go far enough out, you get to the language definition itself, which ultimately must provide some "global" catchall case.

Python makes lexical scope much more complex to describe: Every variable is declared at a module (or REPL), class, or function boundary. To find the boundary where a variable is declared, first you look for the nearest boundary. If you've found a module boundary or a function boundary where the variable is in the parameter list, you're done. Otherwise, you search that boundary for any `=`, `global`, or `nonlocal` declarations of that variable. If you find `global`, you skip to the nearest module boundary, and you're done. Otherwise, if you find one or more `=` declarations and don't find `nonlocal`, you're done. Otherwise, you repeat this process at the next nearest boundary.

I do sympathize with a couple of the pain points you're talking about:

1. If a variable name is written with a typo, Arc's `=` will silently assign to a misspelled global binding. I think it'd be more ideal to alert the programmer to an error like C does.

2. To declare a local variable, an Arc programmer must use things like `let` and `with`, which add layers of parentheses and indentation. In C (ever since C99) and Python, local variable declarations can be performed in the middle of a block, and they don't affect the indentation of the following code.

For point 1, most of the time I like to program without using `=` at all.

For point 2, I think Lisp's prefix notation and lambda notation facilitate a style that uses more deeply nested expressions than you might be used to. When expressions can be more deeply nested, they don't have to be broken apart across quite as many local variables, so writing `let` and `with` forms here and there doesn't pose a serious problem most of the time. That said, I use what I call "weak opening parens" and a certain indentation style to do away with this extra nesting anyway (

This does seem like a weird bug -- but what's the use case? I don't think the url spec ( actually allows them there.

Is it used to figure out how much to auto link, for example, in a comment in HN or this very forum? That's certainly a valid usecase.

2 points by akkartik 2 days ago | link | parent | on: Variables & scoping complaint

I see. Yes, it can be a little sharp-edged for new-comers from other languages that `=` auto-defines globals. It's not immediately obvious that we don't use it much. Let me think about how to improve that.

Thanks for the clarification!

2 points by rain1 2 days ago | link | parent | on: Variables & scoping complaint

I have been thinking about a modified version of LET that takes a sequence of expressions (like begin) that are either assignments or not assignments. Then it would collect all consecutive assignments together into a letrec. For example:

      (= a 1)
      (= b 2)
      (= c 3)
      (= x 4)
      (= y 5)
would get collected into

      (letrec ((a 1)
               (b 2)
               (c 3))
        (letrec ((x 4)
                 (y 5))
and this "LET" form would take place of the implicit begin we have in most contexts. What do you think? Could it be useful.
2 points by sht 2 days ago | link | parent | on: Variables & scoping complaint

He wants it to be a little more like scheme wherein:

   (define (f)
     (define v 10)
creates v as a local variable. In Arc, and most lisps, you need to do:

   (defun f ()
     (let ((v 10)) 
Additionally, Arc has the wrinkle (i think, i haven't used Arc recently) where if you do:

   (defun f ()
     (= v 10)
you create a global variable and assign 10 to it, instead of the python default which creates v in local scope. Basically, he's trying to use imperative programming and doesn't want to declare local variables using let.
1 point by akkartik 3 days ago | link | parent | on: Variables & scoping complaint

Sorry I just saw this. Can you elaborate? What is an example of a variable that C and Python define correctly but has a worse equivalent in Arc? Or what's a variable in Arc that bit you by being globally scoped?

In particular I'm surprised that you mentioned C. If we're worse than C in this respect I'd love to understand that better.

2 points by rain1 3 days ago | link | parent | on: Show Arc: Serializable Closures

I should add: This works because the host lisp is pure: there is no SET! or mutable cells.

If you have mutable cells, write out and read it back in you'd get a clone of the cell - independent of the original. This seems like the wrong behavior.

To make it work with mutable cells seems kind of impossible. I'm not sure. One system I found replaces mutable cells with distributed uniquely identified mailboxes. (termite scheme). is the API, by the way! I should probably mention that somewhere.

Let me actually see if I can come up with a POC first, at least for the canvas and javascript. Realistically, since it's just GET requests that don't need authentication, I shouldn't even need laarc running, I can just send the same requests by AJAX.

Wanna hop into discord and we can chat about the design?

The repo's open, and I could help get you set up with it if you wanted to work on some of this.

It should be a matter of:

  git clone
  cd laarc
  rlwrap bin/arc
  ((load "news.arc"))
and then http://localhost:8080/place

OK... I don't know where I got "single event handler from," that obviously wouldn't be true, but it would still be simpler than having each pixel be a separate HTML form....

why not go all the way and render client-side in a canvas as well?

As it is, the more "pixels" you have, the slower the page loads. You could probably have just a single canvas and a single event handler.

You could preserve functionality for non-js users by using an imagemap (assuming browsers still even support those) or sticking the existing code in noscript tags.

Yeah, it was worth the effort to make the drawing code client side. Someone showed up and made a software rasterizer.


Thanks for mentioning that. It's a bug.

The trick to clear the x is to scroll up and click on the color palette.

Here's a timelapse for the curious.

Much better.

I will say; I did a page reload and noticed the color pick was still in place and had to go hunt for the x. I expected it to reset, but I'm not sure if you see that as a bug or a feature :)

also, it looks like the client side is pure js... Is Lumen not up to that task? just curious if you tried that as it might be nice if, someday, we could get to the point where this kind of stuff could be done in arc.

Kay, it's all client side now. Have fun!

Permalink for posterity

Reads like a really good horror story :)

> I was aware that Arc kills threads that take longer than 30 seconds...

> Sooo yeah, submitting changes via JS is easy. Getting updates is the hard part.

That's why I suggested a post request...

Just deliver the page and create an api end point, on the server, that gives you the last x changes from the change log.

With that ajax request, you could return these net updates for the client and use client side js to apply them to the dom. You could even create a trivial js debounce[1] algo to throttle requests if you wanted to go even further.

1. 'debounce' for those who don't know -> Only I'm suggesting it as a way to throttle ajax reqs.

We tried. It was almost a disaster.

We started out by making an EventSource endpoint and using JS EventSource object to get updates. Seemed to work great.

Pushed it live.

To everyone on the site. Not just to the people on /l/place. Oops. Mistake #1.

Mistake #2: I was aware that Arc kills threads that take longer than 30 seconds, but I was unaware that EventSource automatically tries to reconnect. Welcome to the DoS party.

With no way to tell the clients to stop. Mistake #3.

It was only live for about 10 minutes, but it took around two hours before the last few clients finally refreshed their browser and stopped DoSing the endpoint. The server absorbed the extra traffic like a champ, but the server logs were ridiculous for about an hour. Lots of "client took too long" error messages spit out by Arc every second.

Sooo yeah, submitting changes via JS is easy. Getting updates is the hard part.

Could poll. But then that's still hammering the server. Moreso than it already is.

It's probably a feature that it's painful to use. Only the determined will use it for art.

That said, if anyone has ideas for how to tweak arc for performance for this scenario – and remember to calculate how much memory is used by how many simultaneous sockets are open – I'd be willing to try again.

'Tis a feature, not a bug.

Bonus: the whole thing runs on a $5/mo FreeBSD droplet. Arc's performance is just that good.

The graphs have been incredible:

I guess people really like toys written in arc....

You're right about the DDOS. Someone from the Czech Republic wrote a script to wipe the map. It briefly froze up the server.

I solved that by cloning the endpoint, disabling the old one, optimizing the new one, then rolling back the board by 1 hour. The scripter stopped.

If stuff like that keeps happening, I imagine we can fight it via cloudflare firewall rules.

It looks like it's possible to draw without being logged in.

You might want to fix that, otherwise the whole thing looks like a DDOS attack waiting to happen.

>This is where js would be handy - right? Personally I would just update the dom element and send a http post in the background.

If it's to be done in JS, might as well implement a drawing tool in an actual canvas element.

I've seen tutorials that are reasonably simple. The complicated part would be actually saving it. It is possible to export a canvas as a png and upload it with an AJAX request but I don't know how cross-browser compatible that is.

It's cool, but it's doing a new page request per interaction and the page load takes at least a second. It also has a looong painting operation. :(

This is where js would be handy - right? Personally I would just update the dom element and send a http post in the background.

I get that it's just a toy, but still it shows that languages* should have a good client side story too. Maybe some Lumen integration?

* that are for the web.

edit: reminds me of the million dollar homepage

Stick around! We like submissions :)|programming for general programming stuff




And you can make your own tags:

(That would post a link to /l/whatever, /l/foo, and /l/bar.)

The code is about 100 lines:

Every pixel is a form with a button.