Arc Forumnew | comments | leaders | submitlogin
1 point by fallintothis 5420 days ago | link | parent

I wonder if modules could be implemented with namespaces?

I guess I use the words "module" and "namespace" interchangeably. I'm not sure what else "module" ("package", "namespace", sometimes "library" (loosely), etc.) would mean.

What I meant was that, say, you have two files:

a.arc

  (use "braces-for-table.arc")

  (def table-I-really-want ()
    {foo 1 bar 2 baz 3})
b.arc

  (use "braces-for-set-builder-notation.arc")
  (load "a.arc")

  (def set-I-really-want ()
    { (* v v) for v in (vals (table-I-really-want)) })
You wouldn't want a.arc's use of braces for tables to leak into b.arc, which uses braces for set-builder notation (which you further don't want to clobber the braces in the definition of table-I-really-want).

With a fancier module system, you might even have

b.arc

  (qualify "braces-for-set-builder-notation.arc" s)
  (load "a.arc") ; doesn't qualify its braces for tables

  (def set-I-really-want ()
    s{ (* v v) for v in (vals (table-I-really-want)) })

  (def another-table-I-want ()
    {foo 5 bar 10 baz 15})
Though there shouldn't be a reason you couldn't do something like

c.arc

  (use "braces-for-table.arc")

  (def some-table ()
    {x 5 y 10})

  (use "braces-for-set-builder-notation.arc")
  ; braces hereafter are for set-builder notation

  (def some-set ()
    { x for x in (vals sig) })
As Arc lacks a proper module system, you can already see the clobber-some effects of definitions being global/unqualified. APIs leak all over the place:

  arc> (load "sscontract.arc") ; only really needs to provide sscontract
  nil
  arc> (priority #\!) ; but the user gets all of the implementation details!
  1
Similarly, I don't want to load some library and have implementation-detail reader macros polluting the reader. (If the library's specifically for reader macros, then of course that's okay.)

Even some simple public/private control would be nice. I've played around with this in Arc before. E.g.,

  (let localize nil

    (assign localize
            (fn (expr fs)
              (when (caris expr 'def)
                (if (~mem (cadr expr) fs)
                    `(assign ,(cadr expr) (fn ,@(cddr expr)))
                    expr))))

    (mac provide (fs . body)
      (let private (trues [and (caris _ 'def)
                               (~mem (cadr _) fs)
                               (cadr _)]
                          body)
        `(let ,private nil
           ,@(map [localize _ fs] body))))
    )

  arc> (macex1 '(provide (f g)
                  (def f (x) (h (+ x 1)))
                  (def g (x) (+ (h x) 1))
                  (def h (x) (* x x))))
  (let (h) nil
    (def f (x) (h (+ x 1)))
    (def g (x) (+ (h x) 1))
    (assign h (fn (x) (* x x))))

  arc> (def foo () (prn "outer foo") nil)
  #<procedure: foo>
  arc> (provide (bar)
         (def foo () (prn "inner foo") nil)
         (def bar () (prn "bar") (foo)))
  #<procedure: bar> ; note: no redef warning, since def changed to assign
  arc> (bar)
  bar
  inner foo
  nil
  arc> (foo)
  outer foo
  nil
But this particular approach doesn't interact with macros nicely, doesn't let you qualify namespaces, isn't general, etc. So it's really suboptimal.


1 point by aw 5420 days ago | link

I guess I use the words "module" and "namespace" interchangeably.

By "namespace", I was thinking specifically of MzScheme namespaces, which is where global variables live.

But like you say that doesn't help with macros, so to answer my own question: no, I don't think namespaces are enough to implement modules...

-----