Arc Forumnew | comments | leaders | submitlogin
New version of Arc/Nu (github.com)
5 points by Pauan 4202 days ago | 18 comments


3 points by Pauan 4188 days ago | link

New version:

https://github.com/Pauan/ar/commit/30aa79bbd1082bf182e07d86f...

Now files only export the boxes they create. Which means...

  ; foo
  (def foo ())

  ; bar
  (import foo)
  (def bar ())

  ; qux
  (import bar)
  (prn bar) ; works
  (prn foo) ; error
Basically, "qux" imported "bar" which imported "foo", but "bar" only exported the boxes it defined, thus it didn't export "foo".

This is not only cleaner (and faster), but it opens up the possibility of having two separate Arc versions operating side by side, in the same namespace, able to communicate with each other.

That's important because I really want to have Arc/Nu use hygienic macros and hyper-static scope by default, but that would break Arc 3.1 compatibility. But now I can have Arc/Nu and Arc 3.1 operating at the same time. This was possible before, but was very difficult. Now it's easy.

-----

2 points by Pauan 4188 days ago | link

https://github.com/Pauan/ar/commit/d3971088cdf3160124d9affa7...

Arc/Nu now uses hyper-static scope and hygienic macros by default. This means I had to change "02 arc" in the following ways:

* Rearranged things so that they are always defined before they are used.

* Fixed some code duplication (e.g. alist now uses acons).

* Fixed some places where macros were supposed to use gensyms but didn't.

* Fixed unhygienic macros (like aif) so they work in the new hygienic macro system.

* The various defining macros (def, mac, etc.) all use "var" now rather than "assign".

* The "defs" macro has been changed a bit and now has an actual use.

* Added in a few new macros, like redef, remac, w/sym.

For the most part, though, I tried to change it as little as possible.

Thanks to this, I also found a few typos in the Arc/Nu libraries.

By the way, I made sure to change it in such a way that it works correctly whether hyper-static/hygienic-macros is turned on or off.

And of course, the Arc/Nu compiler can still load Arc 3.1's "arc.arc" unmodified, if you want to do that.

-----

2 points by Pauan 4188 days ago | link

By the way, if you want to write macros that work correctly in both Arc 3.1 and Arc/Nu, here's how.

Non-anaphoric macros should Just Work(tm).

Anaphoric macros (aif, awhen, etc.) need to be tweaked a bit. First, let's look at the definition in Arc 3.1:

  (mac awhen (expr . body)
    `(let it ,expr (if it (do ,@body))))
Now, there's two ways to make this work in Arc/Nu. First, you can unquote+quote:

  (mac awhen (expr . body)
    `(let ,'it ,expr (if ,'it (do ,@body))))
Secondly, you can use "w/sym":

  (mac awhen (expr . body)
    (w/sym it
      `(let it ,expr (if it (do ,@body)))))
I personally recommend "w/sym", since you can just slap it onto the front and be done, but it's up to you.

And that's it. Now your macros work in both unhygienic Arc 3.1 and hygienic Arc/Nu.

-----

2 points by Pauan 4187 days ago | link

After some thought, I decided to stop half-assing it. What I've been trying to do is make a new implementation of Arc that is backwards compatible with Arc 3.1 but adds new features and fixes bugs.

The problem is that eventually I'll run into features I want to add, or bugs I want to fix, and I won't be able to do that without breaking compat with Arc 3.1.

This is very restricting, and part of Arc is about unbridled freedom. I thought about going the pg route and just saying "screw compat!" but if I did that I'd just end up with Nulan, so what's the point?

So instead, here's what I'm gonna do. There will be two separate languages implemented by the Arc/Nu compiler: Arc/Nu and Arc/3.1.

Arc/3.1 is the Arc you know and love. Unhygienic macros, dynamically scoped globals, and most of the warts and bugs and missing features.

Arc/Nu is a language similar to Arc, but with new features, bug fixes, and general cleanup. It has hyper-static scope and hygienic macros. It doesn't try to maintain backwards compat with Arc 3.1.

Now, you might be wondering, what's the point? I mean, we already have vanilla Arc 3.1 as implemented by pg, so why should Arc/Nu support Arc 3.1 at all?

The twist is that thanks to the magical power of booooxes, I can have Arc/3.1 and Arc/Nu running in the same namespace. This means Arc/3.1 can import Arc/Nu stuff, and Arc/Nu can import Arc/3.1 stuff.

And it all works correctly, so that if you define an unhygienic macro in Arc/3.1 and import it into Arc/Nu, it will behave unhygienically. And vice versa, if you define a hygienic macro in Arc/Nu and import it into Arc/3.1, it will behave hygienically.

And you can do things like import an Arc/3.1 library and mutate its stuff, or do the same to an Arc/Nu library. There's no restrictions between the two, because it all runs in a single namespace.

This means you can write new code with all the shiny features, yet still use old Arc/3.1 libraries. And if you just plain like using Arc/3.1 but there's some Arc/Nu library you want to use? You can.

And if pg ever releases Arc 4, I can just add it as a third language, which will let it interact with both Arc/Nu and Arc/3.1. This is all very very easy to do thanks to boxes.

-----

2 points by Pauan 4186 days ago | link

https://github.com/Pauan/ar/commit/2c7c5f8f0ea2f313a47fadb2a...

After some major refactoring, I reverted it back to use vanilla Arc 3.1.

Now, Arc/Nu has a rudimentary "multiple language" feature. When using the "arc" executable, you can now specify the "--lang" property.

For instance, when using "arc --lang foo", it will look for a folder called "foo" in the "lang" subdirectory. This folder should contain a file called "main" which should be written in Racket. Using this file, you can implement custom languages using the Arc/Nu compiler.

Currently, only two languages are supported: "arc/nu" and "arc/3.1"

https://github.com/Pauan/ar/tree/2c7c5f8f0ea2f313a47fadb2ae6...

https://github.com/Pauan/ar/tree/2c7c5f8f0ea2f313a47fadb2ae6...

As you can see, "nu.nu" is quite sparse at the moment, but it does load correctly if you use "arc --lang arc/nu". With some more refactoring, I'll be able to make it so that arc/nu and arc/3.1 can use libraries written in the other language.

-----

1 point by Pauan 4185 days ago | link

https://github.com/Pauan/ar/commit/6352cbffc8866fac7b19ed3b3...

Now multiple languages are fully supported. The way it works is that, within a file, you can use "w/lang" to temporarily change the language. For instance, suppose you had the following "arc/3.1" program:

  (w/lang arc/nu
    (var foo 1))

  (= bar (+ foo 2))
Within the "w/lang" block, it's using "arc/nu", but outside, it's using "arc/3.1"! Using this, it's easy to import libraries written in "arc/nu":

  (w/lang arc/nu
    (import foo))
And vice versa, if you're writing a program in "arc/nu", you can use "w/lang" to import things from "arc/3.1":

  (w/lang arc/3.1
    (import foo))
By the way, because all of this is using boxes at compile-time, there's zero runtime cost. The only downside is that if you use two languages at once, it has to load both of them, which increases the startup time.

-----

4 points by Pauan 4185 days ago | link

Well! I just learned something new! Racket's "procedure-rename" is ridiculously slow. In case you don't know what I'm talking about, it's just a function that lets you rename functions:

  (procedure-rename (lambda () 1) 'foo)
Anyways, here's the timing tests I did for Arc/Nu using "procedure-rename":

  > (+ 1 2)
  Arc/Nu   iter: 45,419,082   gc:   0   diff:  0.00%
  Arc 3.1  iter: 52,867,613   gc: 188   diff: 16.40%

  > (no ())
  Arc/Nu   iter: 26,594,507   gc:   0   diff:   0.00%
  Arc 3.1  iter: 54,532,505   gc: 152   diff: 105.05%
And here's the results when I removed "procedure-rename":

  > (+ 1 2)
  Arc/Nu   iter: 88,933,497   gc:   0   diff: 71.88%
  Arc 3.1  iter: 51,741,236   gc: 116   diff:  0.00%

  > (no ())
  Arc/Nu   iter: 78,026,418   gc:   0   diff: 37.11%
  Arc 3.1  iter: 56,909,869   gc: 156   diff:  0.00%
What a ginormous difference. Removing it doubled the speed of Arc/Nu! Given that the sole purpose of "procedure-rename" is to, well, rename functions, I wouldn't expect it to have such a huge runtime performance penalty, but apparently it does...

-----

3 points by lark 4184 days ago | link

I sometimes wonder if garbage collection in dynamic languages is necessary.

-----

2 points by rocketnia 4184 days ago | link

Sounds like a good topic, and I'd be interested in hearing to hear your thoughts on this. I've been thinking about the same kind of thing, but I'm looking to use it in a weakly typed subset of a statically typed language. My motivation is mostly to see if we can make it convenient to externally manage the memory needs of otherwise encapsulated programs.

This is probably a discussion for another thread. ^_^;

-----

1 point by akkartik 4184 days ago | link

My arc variant uses ref-counting, for what it's worth: https://github.com/akkartik/wart/blob/adf058706b/010memory

-----

1 point by rocketnia 4185 days ago | link

I wonder if the compiler can't see through a 'procedure-rename call to realize it can still apply optimizations to the code. Like, maybe it can optimize ((lambda (x) ...) 2) but not ((procedure-rename (lambda (x) ...) 'foo) 2).

-----

2 points by lark 4186 days ago | link

Does Arc/Nu support file uploads?

-----

2 points by Pauan 4186 days ago | link

Are you talking about this? http://www.arclanguage.com/item?id=16355

Arc/Nu runs Arc 3.1 unmodified, so it behaves almost identically to vanilla Arc 3.1.

It would probably be possible to add it in, but I don't use the server portion of Arc, so that's out of my league. Patches welcome.

-----

1 point by lark 4186 days ago | link

Yes, that's what I'm talking about.

I use the server portion of Arc to write web-based applications, and would like to upload files.

Anarki hadn't worked very well or very fast when uploading. I might just bite the bullet and use web.py alongside Arc, and have Python calling Arc after a file has been saved. I might also resort to using Anarki, although breaking backward compatibility in a few ways can become a bit of a concern.

I wish there were a language that offered what I need.

-----

2 points by Pauan 4202 days ago | link

Rewrote to use boxes. Faster. Cleaner. Has optional hyper-static scope and hygienic macros. Has a great namespace system based around w/include, w/exclude, w/rename, and w/prefix. Still completely compatible with Arc 3.1

-----

3 points by idoh 4197 days ago | link

Thanks Pauan, I'm an Arc/Nu user for my personal projects and I'll be checking it out.

-----

1 point by Pauan 4196 days ago | link

A quick note if you're migrating old code to the new version: the "parameter" macro is gone. Use an ordinary variable and "w/" instead. In other words, rather than doing this:

  (parameter foo ...)
  (w/foo ...)
Do this:

  (= foo ...)
  (w/ foo ...)
Also, "=" still works like it does in Arc, but I recommend using "var" rather than "=", because it's hyper-static:

  (var foo ...)
  (w/ foo ...)
---

Another difference is that keyword arguments are no longer supported at all. This is because it's quite difficult to implement them properly, only a single function in Arc/Nu actually used them, and they're not backwards compatible with Arc 3.1, so I decided it wasn't worth it.

If you run into any other difficulties, feel free to post here and we can work it out.

-----

1 point by Pauan 4196 days ago | link

By the way, if you use "parameter" and can't be bothered to change to the new system, you can use this macro:

  (mac parameter (x y)
    (w/uniq (var body)
      `(do (var ,x ,y)
           (mac ,(sym:string "w/" x) (,var . ,body)
             `(w/ ,',x ,,var ,@,body))
           ,x)))
Why didn't I just include it in Arc/Nu? Because I think the new system is better, so in the long run I really do want people to switch to the new system.

-----