Arc Forumnew | comments | leaders | submit | zck's commentslogin

Whoa, that's fantastic. How difficult was it to set up?

Thanks for doing it!

-----

3 points by fauria 150 days ago | link

A little bit tricky, there were some issues with permissions and shared volumes. If you find any issue just let me know!

-----

3 points by zck 160 days ago | link | parent | on: Unit-test.arc 1.0 incoming (part II)

Heh, no worries. It's taken me, oh, 202 days to update the dang library (I feel like my macro skills have something to be desired, or it would be easier). So no worries about taking four to see this. I was planning on pinging you in a few days if you hadn't seen this.

A coordinated launch would be cool. I'm pretty much ready here; the readme is updated (although it does not explicitly have a version number, which I should add).

But before we get into that, would you mind playing with it a little bit to see if there's anything broken or not working? Thanks.

-----

3 points by akkartik 160 days ago | link

Hmm, strangely I just sent you a pull request to update the Readme. I'm not too familiar with Mercurial or Bitbucket; maybe I'm doing something wrong?

https://bitbucket.org/zck/unit-test.arc/pull-requests/2/upda...

I'll play with it today or tomorrow and make sure all of Anarki's tests update correctly.

-----

3 points by zck 159 days ago | link

Yeah, that was right. Thanks for catching the readme changes -- I guess I had made some but not all.

-----

4 points by akkartik 156 days ago | link

I've updated my script to auto-upgrade Anarki tests[1], and things look pretty good. Just a couple of minor comments:

a) I see a message about redefining assert. Perhaps we should change the name in Anarki or unit-test.arc?

b) The new version complains about duplicate nested suite names inside a test suite. That seems like a reasonable idea, and I just want to confirm that it's intended.

c) If you have a duplicate test name in a suite the error is confusing. Here's the example I ran into from Anarki:

  $ cat x.arc
  (load "unit-test.arc/unit-test.arc")

  (suite cut
    (test finds-element-in-string
      (assert-same '(3 4 5) (cut '(1 2 3 4 5) 2)))
    (test finds-element-in-string        ; duplicate name
      (assert-same "cde" (cut "abcde" 2)))
  )

  (test)

  $ ./arc.sh x.arc
  Can't coerce  #<procedure: cut> string
    context...:
     anarki/ac.scm:1015:0: ar-coerce
      map1
      map1
      string
     anarki/ac.scm:1279:0: aload1
Once you switch to unique names everything works fine. But perhaps we can improve the error message?

[1] I'll post the final script here once we "launch".

-----

4 points by zck 156 days ago | link

Yes, it's a desired feature that a suite can't contain two things with the same name -- either suites, tests, or one suite and one test. This is because I want names to be unique. Saying (test cut.finds-element-in-suite) shuld run only one test.

What you ran into is actually a bug I fixed at a meetup on Tuesday. The current error message is:

  Error: "In suite cut, there are two things named finds-element-in-string."
The commit is here: https://bitbucket.org/zck/unit-test.arc/commits/bb41b4183938.... Can you re-pull (hg pull; hg update) and see if it works then? The most recent commit is 96652e5.

-----

3 points by akkartik 156 days ago | link

Ah, you're right. Looks great now!

-----

4 points by zck 196 days ago | link | parent | on: Ask Arc: How to improve the Arc ecosystem?

I think it would be useful to have things built in Arc. That way the language can feel like there's more life in it. Right now there aren't too many things built in Arc that aren't part of the language ecosystem.

To promote that, it would be useful to have a page that lists things built in Arc. I just made a page on the Anarki wiki here: https://github.com/arclanguage/anarki/wiki/Things-built-in-A...

-----

3 points by akkartik 196 days ago | link

Great idea! You should put your unit-test.arc in there.

Edit: added a couple of things.

-----

3 points by zck 211 days ago | link | parent | on: How to run anarki as utility, not REPL?

Just echoing that rlwrap isn't needed. I actually added an arg (-n) to arc.sh that doesn't use rlwrap. I use it when running arc inside an emacs shell, because emacs has terminal integration that I prefer.

-----

3 points by jsgrahamus 211 days ago | link

I started using ansi-term in emacs to launch a shell file which wrapped rlwrap around the file I wished to execute. Turns out that M-x no longer works in that buffer.

-----

2 points by zck 226 days ago | link | parent | on: Errors in anarki stable

Hrm, perhaps it shouldn't be called "stable". That suggests a more-tested release cycle. Maybe something like "original" or "pure", or even "3.1-release"?

I like the idea of having something that's what was originally released, but doesn't really suggest that it's what someone should use if they're new to Arc.

-----

4 points by akkartik 226 days ago | link

Well, we do also have 'official' which is exactly what was released.

I think the intent is that 'stable' is guaranteed to be backwards compatible with 'official'. So the real issue is that 'official' is stale.

-----

2 points by zck 248 days ago | link | parent | on: Y combinator in arc

I agree; the nested case is a bit difficult for humans to parse.

I wonder if there's a way to make (fn (x) ...) even more lightweight.

What if, to do the same thing, we had a new anonymous function syntax?

    {x ...}
It would work somewhat like this:

    arc> (let my-fn {arg (string "I got " arg)}
              (my-fn "this thing"))
    "I got this thing"
This is somewhat analogous to "let"

    (let x ...)
It could also allow for multiple arguments, like this:

    {(x y} ...)
Allowing for multiple arguments prevents destructuring-bind style function calls, though, which is a downside. I guess you could use other kinds of brackets for that?

    {{x y} ...};; this would be non-destructuring-bind
    {(x y) ...};; this is destructuring-bind
    {{(x y} ...);;; this is the same as #2; it would destructuring-bind the first argument, a list.

Heck, we could even build it into the existing anonymous function syntax:

    [{x y} ...]
Would be the same as

    (fn (x y) ...)
But I'm not sure that's a big enough win.

-----

3 points by mpr 248 days ago | link

As per akkartik's comment, we already have multi-argument anonymous functions in anarki:

    ([prn _1 _2] "hello " "there")
But yeah maybe having full lambda list capabilities in the anonymous function would be cool.

    ([((a b) c) (prn c b a)] (list "is" "name ") "my ")
So if the first argument to the bracket function is a list, it acts as a lambda list.

But this interferes with the arc special syntax of having lists act as functions on their indices. Because the following is already valid arc code:

    (let x (list 1 2 3)
      (x 2))
    ;; > 3
In that case having different delimiters might be the way to go. So your brace notation would be used for anonymous functions with full lambda list capability.

    (let x (list 1 2)
      ({((a b) c) (prn c b a)} x 3))
Edit: trying some other formatting...

    (with (f {((a b) c)
               (prn c b a)}
           x (list 1 2))
      (f x 3))

-----

3 points by zck 248 days ago | link

I was thinking that if you have an even simpler way to bind specific variables in the function call, you can nest these anonymous functions, and not have the arguments shadow each other.

> In that case having different delimiters might be the way to go. So your brace notation would be used for anonymous functions with full lambda list capability.

Yeah, I think you're right. The square-brace anonymous function could have optionally a curly-braced first argument. If that argument isn't there, it works as the square-braced anonymous function currently does. If that argument is there, it's the arguments to that function. Since curly braces aren't used anywhere else in Arc, it can only be parsed in that one way.

But perhaps this is all a lot of work to avoid writing `fn (arg1 arg2)`. Other than golfing, I don't know if you really want to nest functions this way. And this seems like a waste of the only paired characters Arc doesn't use.

-----

3 points by rocketnia 248 days ago | link

"And this seems like a waste of the only paired characters Arc doesn't use."

I don't think even the [] syntax really pulls its weight. Between (foo [bar baz _]) and (foo:fn_:bar baz _), the latter is already more convenient in some ways, and one advantage is that we can define variations of (fn_ ...) under different names without feeling like these variations are second-class.

(Arc calls it "make-br-fn" rather than "fn_", but I wanted the example to look good. :-p )

-----

2 points by zck 248 days ago | link

Interesting.

Personally, I've never gotten comfortable with the colon intrasymbol syntax. Even in your example, I'm having trouble parsing it right now. I really don't like how it makes "bar" look like part of the first part, not the second.

-----

5 points by zck 248 days ago | link | parent | on: Implicit importing

> I know Emacs Lisp has this sort of functionality -- so should Arc have something similar?

Emacs's autoloading is just about making startup faster. Autoloads are pieces of code that say "There's a function named `#'foo` in file `bar.el`". Yes, you don't load bar.el, but you do have to load `bar-autoloads.el`, which is the file that contains the autoload pointers. I'm not sure it's a win, bureaucratically. There's some documentat about Emacs autoloads here: https://www.gnu.org/software/emacs/manual/html_node/eintr/Au... .

There's a difference between included libraries and non-included libraries. You make this point pretty clearly in your post, but I saw "Emacs" and jumped to that sentence. Right now Arc loads all included libraries. Is there a particular reason you want to not do that? It seems like the main advantage is startup speed, in which case I wonder if we could just profile^1 and optimize Arc, and get better results from the same amount of work that it would take to write some sort of autoload system.

[1] pg's talked several times about profilers being vastly important^2, 3. It's a shame there isn't one in Arc.

[2] From http://paulgraham.com/arcll1.html,

> From very early, maybe from the begining, the Scheme spec said that conforming implementations must do tail call elimination. The first time I read this, I thought "wait, can you require this in a spec?" Arc will see this increase, and raise it by some standards for profiling.

> The way to get fast code in Arc will be to profile it and then add declarations that improve efficiency where needed.

[3] From http://www.paulgraham.com/langdes.html,

> Users don't need benchmarks to run fast. What they need is a language that can show them what parts of their own programs need to be rewritten. That's where speed comes from in practice. So maybe it would be a net win if language implementors took half the time they would have spent doing compiler optimizations and spent it writing a good profiler instead.

-----

4 points by digitalis_ 248 days ago | link

If (when!) Arc becomes the 100 Year Language that we all want it to become, it's various libraries will become rich and numerous.

On the one hand, I don't want my .arc files filled with boilerplate code to load the libraries I want; on the other, I don't want a huge number of functions to be loaded that I won't actually use.

I feel that autoloading is the perfect compromise: granted, the 'autoload pointers' will have to be loaded (by default and automatically -- otherwise that's just more boilerplate) -- but this yields far less overhead than loading the actual functions.

For big programs, pg's dead right: far more of the speed will come from optimising the program -- however, for small, sysadmin-type programs, where your program is so small that your algorithm is already optimal, but the actual problem is quite large (e.g. a gargantuan directory structure), the speed comes from a tight language. (And you'll write far more of these microprograms in your lifetime than big, optimisable programs.)

Please don't get me wrong: I agree with you wholeheartedly that there should be a profiler in Arc, and that this should be used to optimise Arc --

And I don't think it needs to be an either-or.

-----

5 points by zck 248 days ago | link

>...I don't want a huge number of functions to be loaded that I won't actually use.

What's the concern here? I don't really care how many functions are loaded, even if I don't use them, because it doesn't affect me.

Now, startup time? That effects me. But I don't know how much of the startup time is because of loading more functions.

Alternately, name collisions? I don't see that as a giant issue, and isn't solved by autoloading anyway.

> And I don't think it needs to be an either-or.

I agree. I'm just not all that sure what autoloading gets us. I'm not against it, per se, I just think it's something moderately complicated that might not help us get what we want.

Edit: Also, welcome! Glad to see someone new here. Feel free to contact me off-forum if you like; my email's in my profile.

-----

4 points by digitalis_ 248 days ago | link

I think I've been misunderstanding something here, and your posts have cleared this up for me. (So, thank you!)

For some reason (and believe me, it seems stunningly obvious to me now), I was under the impression that loading a load of functions into memory would somehow not only affect startup, but also the speed of programs after startup. (ik, ik) I think I've sidetracked myself from my original goal of discussing ways of getting rid of typical '#include'-esque boilerplate.

Though my argument about already-optimal small programs (which have a large workload) might apply to compiler optimisations, it has little to do with autoloading.

I think autoloading would become useful if startup time were pushed up to anything more than a second -- after that, I think most people (that is, I) get quite angry!

Again: thanks for clearing this up for me.

Moving on from autoloading: how are name collisions dealt with in Arc? The only thing I can think of is the old elisp "prefix all yer functions with the package name" ideology. (So the functions of the string library would be called `string-foo`, `string-bar-baz-qux`, etc.) This'd be important, given that (one way or another) ALL THE FUNKSHUNZ are loaded.

-----

4 points by zck 248 days ago | link

> For some reason (and believe me, it seems stunningly obvious to me now), I was under the impression that loading a load of functions into memory would somehow not only affect startup, but also the speed of programs after startup.

It might! I wouldn't heavily bet on it, but I don't actually know. We certainly could^1 test it! We probably should! But if it doesn't change it much, I think the autoloading isn't worth the complexity cost.

> I think I've sidetracked myself from my original goal of discussing ways of getting rid of typical '#include'-esque boilerplate.

Yeah, that happens. They're certainly both worthwhile conversations.

> I think autoloading would become useful if startup time were pushed up to anything more than a second -- after that, I think most people (that is, I) get quite angry!

Yeah. Certainly right now I wouldn't write something small that I want to use from the command line in Arc (e.g., a Unix utility), because of the runtime. It would be nice to be slower.

> Moving on from autoloading: how are name collisions dealt with in Arc? The only thing I can think of is the old elisp "prefix all yer functions with the package name" ideology. (So the functions of the string library would be called `string-foo`, `string-bar-baz-qux`, etc.) This'd be important, given that (one way or another) ALL THE FUNKSHUNZ are loaded.

Defining a function with the same name as an old one overrides the old one's behavior. So yeah, you either hope nothing collides or you prefix it somehow^2. This is less of an issue in Arc than it is in Emacs both because fewer functions come in the box, and because fewer libraries are pulled in. But certainly collisions can/will happen.

[1] The obvious way I think of is by removing a bunch of unused things from various files that make up Arc, and then see if either startup time, or runtime of a sample program changes.

[2] In my emacs code lately, I've been preferring using a slash, like zck/do-some-stuff. At one point, 5% of the characters in my minesweeper implementation were these prefixes. (https://bitbucket.org/zck/minesweeper.el)

-----

4 points by akkartik 247 days ago | link

"Defining a function with the same name as an old one overrides the old one's behavior. So yeah, you either hope nothing collides or you prefix it somehow. This is less of an issue in Arc than it is in Emacs both because fewer functions come in the box, and because fewer libraries are pulled in. But certainly collisions can/will happen."

Just to add to this, and at the risk of boring the veterans here to death by repeating myself :)

Reading between the lines of the implementation, I think the Arc way of dealing with the possibility of collisions is to not worry about them until they happen. When they happen Arc will show you a warning:

  *** redefining foo
And it's up to the programmer to manually decide how to fix the collision.

This makes a lot more sense than adding prefixes because the names chosen are in the context of the application being built rather than some one-size-fits-all name chosen by a library. That makes them likely to be better names in the context of the application.

Avoiding prefixes also keeps most names from becoming unnecessarily long when they don't need to be.

It would be tedious to have to do this if you have a lot of collisions. But that's a good source of pressure to keep the codebase small and minimal and not pull in a lot of libraries, as people are wont to do in Ruby or Node. Any sort of namespacing mechanism encourages programmers to take less responsibility for their code.

-----

4 points by digitalis_ 247 days ago | link

[There doesn't seem to be a reply button under your last reply -- we've possibly hit a maximum depth -- so I'm replying here. Sorry!]

I'm talking about "a namespace mechanism" here, without actually knowing how one in Arc would work.

Just thinking about it for a moment, I think you'd set the prefix

  (= namespace-prefix 'awesome-package)
and then there'd be some symbol (in the textual sense) that you'd put in front of all the library functions; maybe a slash.

  (def /awesome-function (...)
    (...))
Or, instead of setting the namespace with a variable, you'd have

  (w/namespace awesome-package
    ...
    (def /awesome-function (...)
      (...))
    ...)
[I think the latter's probably better -- it's clearer where the namespace ends.]

In the end, you have to have some way of avoiding conflicts -- and all of these boil down to tacking something on the front (math.sqrt in python, for instance); I (personally) would rather have a better way of doing this than manually typing out `awesome-package` at the start of every function/macro/variable/whatever.

(Though we may eventually have to "agree to disagree" on this, I think the discussion's worth it!)

-----

4 points by akkartik 247 days ago | link

Yup!

The trick for replying deep in discussions: click on the 'link' of the comment you want to reply to. news.arc hides links to replies below some depth for some period of time to discourage flame wars. You can see the code for this at https://github.com/arclanguage/anarki/blob/15481f843d/lib/ne...

-----

2 points by digitalis_ 247 days ago | link

Thank you for the enlightenment! (I promise not to abuse this power.)

-----

4 points by digitalis_ 247 days ago | link

Interesting...

I think, given that Arc is supposed to be "a language for good programmers" [1], that it's silly to impose restrictions like withholding a namespacing mechanism to encourage a certain type of programming.

Though I like keeping codebases minimal, I also like freedom.

[1] http://paulgraham.com/design.html

-----

3 points by akkartik 247 days ago | link

To my mind it is namespaces that add restrictions. Arc's warning about redefining names can be ignored, but a namespace mechanism is usually more insistent about violations.

I try not to use words like 'freedom' in these discussions because navigating by them is a subtle business. While having a feature can sometimes provide freedom, in general I tend to assume that features cost freedom. Like the saying that your possessions own you. A namespace mechanism is more code to write, more places for bugs to be hiding in, more errors for the user to run into, more places for one programmer to hide things where they can trip another programmer up. All these issues are places for degrees of freedom to be used up rather than created.

So yes, we are absolutely in agreement that Arc is for good/experienced programmers. But there are multiple visions out there for how you go about helping experienced programmers. My vision is admittedly unconventional, a minority view. It's possible that Arc just doesn't have namespaces because the authors haven't gotten around to implementing them yet. But somehow I doubt that.

-----

2 points by Pauan 231 days ago | link

Actually, because Node.js has a proper module/namespace system, people are instead encouraged to create a lot of micro libraries (e.g. less than 200 lines of code).

So rather than importing a single big library in your application, you would instead import a lot of micro libraries (each of which is versioned separately, and might have their own dependencies).

There are pros and cons to big libraries, and pros and cons to little libraries. I think languages should have good support for both.

-----

1 point by akkartik 231 days ago | link

Yes, I love the trend towards micro libraries because they encourage people to pull in precisely the functionality they need. That aspect of Node is not part of the problem.

-----

2 points by Oscar-Belletti 247 days ago | link

I agree that prefixes are not a good solution. And namespaces is more code to write both in app's code and in the arc implementation code.

However, if you use two libraries which make a collision, what do you do?

-----

3 points by akkartik 247 days ago | link

In principle I don't have a fully general solution yet :/ It's something I'm working on.

What I would like to happen is that my application only contains dependencies it really needs, and that each dependency includes no superfluous/dead interfaces or code. Under these circumstances I would like to live in a world where I can go in and modify the libraries to have different names, with the difference in names making sense in the context of the application. Then I would bundle the application with all its libraries included.

Of course this doesn't scale to large libraries, because managing a fork today involves an amount of work that ranges from non-trivial to intractable. But this would be my ideal.

Past writings on this subject: http://akkartik.name/post/libraries; http://akkartik.name/post/libraries2. My current project which tries to make fork-management tractable: https://github.com/akkartik/mu

Bear in mind that it's only a hard problem for collisions in the interface of the two libraries. Functions that are used only internally can be wrapped inside closures so they're only accessible to the library that cares about them.

-----

3 points by rocketnia 247 days ago | link

I've been noticing continuities between social code distribution, modularity, and variable scope. A guiding example is code verification:

  Unrecorded reasoning, existing mainly in our minds.
  -->
  Codebases dedicated to proofs or tests.
  -->
  Proofs or tests located in the codebase they apply to.
  -->
  A type/contract declaring a module interface.
  -->
  A type/contract annotation for a function definition.
  -->
  A type/contract annotation for an individual expression.
  -->
  A type/contract annotation for an individual built-in operator, but at
  this point it becomes implicit in the operator itself, and we just
  have structured programming, enjoying properties by construction.
Verification is a simplified version of a build process; it's just a build with a yes or no answer. So the design of a build system has similar continuity:

  Unrecorded how-to knowledge, existing mainly in our minds.
  -->
  Codebases or how-to guides dedicated to curated builds (e.g. distros).
  -->
  Build scripts and docs located in the codebase they apply to.
  -->
  Macroexpansion-time glue code, importing compiler extensions by name.
  -->
  Load-time glue code, importing runtime extensions by name.
  -->
  Service-startup-time glue code, obtaining dependency-injected fields
  by name.
  -->
  An expression, taking free variables from its lexical scope by name.
  (This is a build at "evaluation of this particular expression" time.)
There might be some rough parts in here. I might be taking things for granted that I don't want to, like taking for granted that we want unambiguous named references from one module to another. My point with this continuity is to note that if I don't want named imports, then maybe I don't want named local variables either; maybe tweaks to one design should apply to the other.

And this means that even local syntactic concerns extrapolate to social decisions about how we expect to deal with our unrecorded knowledge. Every design decision has a lot to go by. :)

---

Another exciting part is that I think nested quasiquotation shows us a more general theory of lexical locality. If we're dealing with syntax as text, then locations in that text have an order, and we can isolate code snippets at intervals along that order (and mark them with parentheses). Intervals are partially ordered by containment, so we can isolate code snippets at meta-intervals between an outer interval and multiple nonoverlapping inner intervals (and mark them with parentheses with nonoverlapping parentheses-shaped holes: quasiquotations).

That "nonoverlapping" part seems awkward, but I think there's a simple concept somewhere in here.

With this concept of intervals, I'm considering higher degrees of lexical structure past quasiquotation, and I'm considering what kind of parentheses or quasiquotations would exist for non-textual syntaxes.

A module system deals with a non-textual syntax: The syntax of a bundle of modules. If the modules have no order to them, then we don't even have parentheses to work with, let alone quasiquotation. But they can have an order to them. We can impose one from outside:

  Module A precedes module B.
And anything we can impose from outside, we might want to add as a module:

  Module A says, "..."
  Module B says, "..."
  Module C says, "Module A precedes module B."
This is prone to contradictions and ambiguities. If we can say how to resolve these ambiguities from the outside, we should be able to do so as a module:

  Module A says, "..."
  Module B says, "..."
  Module C says, "Module A precedes module B."
  Module D says, "Module B precedes module A."
  Module E says, "If module C and module D disagree, listen to module C."
  Module F says, "If module C and module D disagree, listen to module D."
  Module G says, "If module E and module F disagree, listen to module E."
This should lead to a very complete system of closed-system extensibility: For any given set of modules, if the set's self-proclaimed ordering between A and B is currently unambiguous, then we might as well listen to it! If we don't like it, we can add more contradictions and disambiguations until we do, right up to and including "Ignore all those other modules and do it like this." :)

With this ability to disambiguate when things go wrong, we can model lexical scope:

  Module A says, "Export foo = (import bar from system {B, C})."
  Module B says, "Export foo = 2."
  Module C says, "Export bar = foo + foo."
  
  Result: foo = 4.
While both A and B have an export named "foo," this conflict is disambiguated by the fact that module A is treating {B, C} as a local scope. I intend this to mean that bar isn't at the top level either.

If we really want access to bar at the top level, we can refer to it again, and we can even be sloppy about it and make up for our sloppiness with disambiguations:

  Module A says, "Export foo = (import bar from system {B, C})."
  Module B says, "Export foo = 2."
  Module C says, "Export bar = foo + foo."
  
  Module D says, "Export all imports from system {B, C}."
  Module E says, "If A and D export the same variable, listen to A."
  
  Result: foo = 4; bar = 4.
If we want, we can have the top-level bar see the version of foo exported by A, even though the version of bar used by A still uses the foo from B:

  Module A says, "Export foo = (import bar from system {B, C})."
  Module B says, "Export foo = 2."
  Module C says, "Export bar = foo + foo."
  
  Module D says, "Export all imports from system {A, B, C}."
  Module E says, "Export all imports from system {C, F}."
  Module F says, "Export foo = (import foo from system {A, B, C})."
  Module G says, "If D and E export the same variable, listen to D."
  
  Result: foo = 4; bar = 8.
Not easy enough to extend? Define some structure. Write modules that assign folksonomic tags to other modules or themselves, and then refer to the system of all modules with a given tag. Write modules that act as parentheses, and write modules that determine enough of an order to decide which modules those parentheses contain. Here's an example of the latter:

  Module A says, "Export foo = (import bar from range R1)."
  Module B says, "Export interval R1, and begin it here."
  Module C says, "Export foo = 2."
  Module D says, "Export bar = foo + foo."
  Module E says, "End interval."
  Module F says, "These modules are in order: B, C, D, E."
The flexibility is obviously really open-ended here, and it's going to be a challenge to make this a well-defined idea. :-p

-----

2 points by Oscar-Belletti 247 days ago | link

>What I would like to happen is that my application only contains dependencies it really needs, and that each dependency includes no superfluous/dead interfaces or code.

Do you want to avoid the situation, wich happens in c, where when you need the sqrt you have to include the whole math file? I totally agree.

>Under these circumstances I would like to live in a world where I can go in and modify the libraries to have different names, with the difference in names making sense in the context of the application

This looks right to me. Perhaps it could be something like python's

    from library import function as good_name_for_your_project
>Then I would bundle the application with all its libraries included.

I'm not sure making a (even not full) copy of a library is a good idea because it would lead the user to have many copies of the same libraries. On my windows machine I ended having 4 versions of python! I think that common parts should be in common.

-----

3 points by akkartik 247 days ago | link

> Do you want to avoid the situation.. where when you need the sqrt you have to include the whole math file? I totally agree.

Yes, definitely. In the Javascript world it's called tree-shaking: https://medium.com/@Rich_Harris/tree-shaking-versus-dead-cod...

> from library import function as good_name_for_your_project

What's happening here is that you're a) adding a feature in Python to support 'from..as', b) including an external library and c) continuing to keep around an old name that you don't really care about. You're essentially preserving the old name just because other people who your application doesn't care about use it.

Imagine a world where maintaining forks was tractable. Would this still be a good idea? Why not just do a search and replace and maintain a private fork, eliminating all this complexity in your private stack? Just delete 'from..as' from your private Python! :o)

> I'm not sure making a copy of a library is a good idea because it would lead the user to have many copies of the same libraries.

Yes, this is a fundamental difference in outlook/ideology. I think that copying isn't always bad. We culturally tend to emphasize the issues with copying a lot more than the costs of avoiding duplication.

A degenerate example is to observe that there are tons of 'e's in the novel I'm reading and try to deduplicate them. That is of course obviously farcical, but it at least serves to illustrate that there's a trade-off, and that always DRY'ing your code isn't obviously a good idea. Another example is to observe that the internet has many copies of the same libraries running at any given time. You can argue that they're on different machines, but then imagine a 'machine' consisting of multiple cores and private caches and non-uniform memory access and RAID-partitioned disks. Changing latency costs can make it reasonable to maintain multiple copies of some immutable data in a single 'machine'. Now consider that development is yet another cost that is open to variation. If (automatically) creating copies of something eases development, it's at least worth considering. For example, optimizing compilers can sometimes specialize a function differently for different callsites. That's duplication often inside a single binary, and it makes sense in some contexts.

The npm eco-system promiscuously duplicates dependencies inside the node_modules/ directory, so that is at least some evidence that the approach I'm suggesting isn't too insane :)

-----

2 points by Oscar-Belletti 246 days ago | link

Ok, this maybe could be the way to go. Adapting little libraries isn't a problem, and it probably makes your program better. This defeats collisions, useless code and is ok for autoloading. But this approach will work only if our libraries will be small enough. For now this is ok.

Duplicating libraries isn't a problem: disk space for ease of development is an exchange which is getting more and more convenient.

For autoloading: the interpreter/compiler could load all .arc files in current directory (or current-directory/lib), or scan them for function definitions (without loading them) and making elisp autoload automatically for every function. I prefer the first option.

-----

2 points by digitalis_ 247 days ago | link

One possibility for this bundling is that Arc looks first where it would expect a library to be (in an equivalent of npm_modules), then looks for it in the usual place (/usr/lib or wherever).

Or, if it all needs to be bundled, you could have symlinks for the libraries you don't change.

What do you think?

-----

2 points by digitalis_ 247 days ago | link

Thing is...this is about as verbose as you can get!

If a name's already good, you're not going to change it; if it's bad, you should push that change upstream! (If the name's bad, it's likely that the original author didn't put much time into choosing the name, so I think it would be fairly straightforward to get that merged.)

[As much as I love this idea of implicit importing, I'm sure the explicit side -- which'll let you change whatever names you like -- will need to be there as well. So we can all chill.]

-----

3 points by rocketnia 247 days ago | link

Quality of a name is relative to a purpose. The more public we go, the more meanings compete for a single name, making us resort to jargon. If a language really only uses homogenous intensional equality, being able to call it = is a relief. If someone wants to build a side-by-side comparison of several versions of an extension, they might prefer for some of the names to be different in every version while others stay the same.

But it's not just names per se. In that side-by-side comparison, they might also want to merge and branch parts of the code whose assumed invariants have now changed; invariants can act as Schelling points, like invisible names. Modifying code is something we do sometimes, and I think akkartik wants to see how much simplicity we'll get if everyone who wants a simpler system has the tooling support to modify the code and make it simpler themselves.

Personally, I find it fascinating how to design a language for multiple people to edit the code at the same time, a use case that can singlehandedly justify information hiding, modules, and versioning. But I think existing module systems enforce information hiding even more than they have to, so that in the cases where people do need to invade that hidden information, they face unnecessary difficulties. I think a good module system will support akkartik's way of pursuing simplicity.

But... my module system ideas aren't finished. At a high level:

- You can invade implementation details you already know. You can prove this by having their entire code as a first-class value with the expected hash.

- You can invade implementation details if you can authorize yourself as their author.

-----

2 points by akkartik 247 days ago | link

"If a name's already good, you're not going to change it; if it's bad, you should push that change upstream! (If the name's bad, it's likely that the original author didn't put much time into choosing the name, so I think it would be fairly straightforward to get that merged.)"

Not necessarily. 'Good' and 'bad' are not absolute, they are extremely contextual. A name that is good for a general-use library might be sub-optimal for your application, or vice versa. Subjective taste is also a thing. So while you should certainly send out a pull request for the change, our model of the world shouldn't rely on the change actually getting pushed.

In general it is amazing to me how often a blindingly obvious Pull Request gets rejected or just sits in the queue, untouched. There's lots of different kinds of people out there. Which is why I tend to think more like a barbarian[1] about collaboration: think of other people as islands with whom you might collaborate if the stars align. But don't rely on the collaboration. Be self-sufficient.

[1] http://www.ribbonfarm.com/2011/03/10/the-return-of-the-barba...

---

"As much as I love this idea of implicit importing, I'm sure the explicit side -- which'll let you change whatever names you like -- will need to be there as well."

I actually interpreted your original post that kicked off this thread as implicit loading since Arc has no notion of modules or import. So the question of changing names did not arise. That seemed like a tangent to the original question.

These seem like separate questions:

1. Should Arc know how to react with implicit symbols?

2. Should Arc provide namespaces?

One the one hand, you can have implicit loading without needing a module/namespace system. On the other hand, I don't see how you can have implicit loading in the presence of namespaces. Without the "from..as" construct how would your system know which library to load a symbol from, if there's a collision?

Summary: even if you have namespaces, you're still going to be doing your own collision-detection if you want implicit loading. What's the point of a module system then?

-----

3 points by digitalis_ 247 days ago | link

Is there a naming scheme for Arc? From reading the stuff that's already out there, I found `w/uniq`, which I suppose is shorthand for `with-unique` -- which means that, for consistency, all other "with"-type functions/macros should be "w/".

For example:

string-to-number, or string->number, or string->num, or str->num, or ston, or ...

1. Whatever's chosen needs to be consistent (i.e. it should always be "str" -- or "string" -- but not a mix).

2. When choosing, readability and terseness need to be balanced.

(I have a feeling this is really a new discussion, and if this does start to kick off, I'll start a new thread.)

[BTW, I do prefix my stuff (that I don't share -- so init code) with "daio/"; but if I was going to put it in a package, I'd use the package name and a hyphen (so "minesweeper-sweep", or whatever).]

-----


>If you are going to get into programming Lisp with Emacs, you should look into Evil (vim bindings for Emacs), paredit (smart paren editing), ac-slime (autocomplete for slime), show-paren-mode (shows matching parens), and undo-tree (a better version of undo/redo).

Yes, customizing Emacs is really useful for making it better to use. To help with that, here are some of my config's settings for things you've mentioned. My show-paren-mode settings are here (https://bitbucket.org/zck/.emacs.d/src/default/init.el?filev...).

Instead of paredit, I use smartparens. They do similar things, but when I looked at the two, I thought smartparens was better, although I can't remember why right now. My config is here (https://bitbucket.org/zck/.emacs.d/src/default/init.el?filev...).

I should similarly check out the other things you've mentioned (except Evil, 'cause I don't like modal editing).

-----


More Arc implementations would be cool, but I don't know if that's the thing preventing Arc from gaining popularity.

Of course, in that sentence I assume "gaining popularity" is the goal. I do think it's a very worthwhile goal, but it might not be yours. And that's fine.

-----

3 points by highCs 298 days ago | link

It's not about popularity. It's about that I, as a good programmer, doesnt use Arc because it sux for a couple of reasons, which defeat the purpose of the language. In my opinion, switching to CL would fix those issues and open up a bright future.

-----

3 points by zck 297 days ago | link

That's fair. Reading your post, it seems like you have four points:

1. Arc is slow. 2. Arc doesn't have threads. 3. You can't make an executable out of Arc. 4. If you're dealing with extending the low layers of Arc, you need to use Racket.

We don't need to switch to CL to solve #1 and #2 -- you can make Racket-Arc faster and add threads there. I'm not sure if switching is required for #3, but #4 is definitely only solved by switching languages.

I think I prioritize popularity more than other people; perhaps because I want libraries, and other people can write more libraries than I can. For example, see my long-coming rewrite of unit-test.arc, which is going to be out any season now.

I also have a possibly unwarranted hope that there will be a new official version of arc, or pg/rtm/kogir/sctb will hang out here more.

I guess my point is that switching to CL fixes some problems; some don't need a switch. And I worry about fragmentation.

-----

4 points by akkartik 297 days ago | link

Just as a counter-point, I'm utterly unconcerned about fragmentation. This community is small, and the Arc codebase is small, in the grand scheme of things. It's tractable for one person to hold it in his/her head. We all have different strengths and weaknesses. If somebody finds it easier to work with C++ (that's me), go do it. If Common Lisp is your forte, and you find it easier to port Arc to it than to build threads into Racket-Arc, go for it. Regardless of where you are, it's tractable (though not trivial; write lots of tests!) to share code across projects.

One lament that often comes up with programmers is why software can't be as stable as a house or a bridge or whatever. Well, the reason is that our forebears tried lots of different houses and bridges before we settled on the ones we see today. That was only able to happen because of large amounts of fragmentation, only we don't call it fragmentation because atoms are harder to copy than bits, we just call it "trying again". Since bits are easy to copy, software culture has internalized some amount of "peer-pressure copying" under the banner of "avoiding fragmentation". I think it's silly. Particularly in the context of a small-scale project where there's never going to be much demand for deploying at scale, we'll never be a massive target for black-hat folks (so quickly transmitting security fixes isn't a priority), etc. Even for a large-scale project like Android, I think the problems people attribute to "fragmentation" are symptoms of deeper issues, and not fragmenting just keeps us from better understanding the issues.

-----

3 points by zck 297 days ago | link

That's fair. I definitely have a bias away from creating architecture, which probably explains more of my reactions than I'm comfortable with. I normally prefer to make things work within an existing system.

But yeah, I do see that it's worthwhile to try random things; it just doesn't feel true to me. For some reason, waterfall design is what makes me more comfortable.

-----

3 points by highCs 297 days ago | link

I see what you mean. I entirely agree with you. Basically, I would not want too to advocate for a switch if it was for minor reasons (even for most medium ones) that can be fixed or with which one can live. That happens a lot with software, you have to live with some shit and that's ok. I think my point goes beyond however.

For understanding why, let's discuss one aspect of software. There is something cool about software that actually many organisation miss I think. Software is pretty predictable. Just use your stats. So, if your development team was going at that velocity this month on that system, chances are they are going to move forward with the same velocity or so the next month. If you've had 15 new bugs this week on your system, chances are you gonna have at least 10 new bugs next week. If you had important successes with your system, chances are you gonna continue to be successful with your system again.

In other words, if your team is slow this month, they won't be fast next month. Nah, they wont. If you had bugs last week but think you've made big fixes, well you gonna be disappointed this week when you will understand that you've not fixed the mother of all bugs because there is no such thing. Your codebase has that property, it has that bug stats. It can go down, but using a continuous and low varying function.

If you adopt Arc and got 5 technical problems in 2 weeks all more or less related to Racket [0], chances are, that's my point, that you gonna have technical problems all along. So what I'm trying to do here by my call is not to fix a couple of issues. What I'm trying to do is to change the stats themselves. Arc must be smooth. If it's not smooth, hackers wont use it. Right now, Arc is unusable because, as you use it, you understand that statistically, Racket gonna pose problems. So you quit.

Note that I'm not advocating fragmentation. I'm advocating to, if reviews and discussions tell it's right, deprecate the Racket version for a CL one.

I've very quickly tried the Clamp implementation yesterday, and already, I've felt the difference. The ffi, check. As fast as C, check. Threads, check. Not repl problem in sublime, check. Easy import from CL, check. Executable, check (I've made one with clamp, it just worked). (Chances are, Im gonna continue to check at this rate.)

I think that makes my point more clear. Before any consideration, we must have a real good implementation hackers would use, as a foundation on which to build on. I can be wrong though. I may be making a judgement mistake of course.

[0] I've also had problems importing my symbols coming from a ffi to arc. Such a pain. It's already working with clamp though...

-----

3 points by zck 297 days ago | link

> If you adopt Arc and got 5 technical problems in 2 weeks all more or less related to Racket [0], chances are, that's my point, that you gonna have technical problems all along.

> Right now, Arc is unusable because, as you use it, you understand that statistically, Racket gonna pose problems. So you quit.

I've had the complete opposite experience -- none of my problems with Arc are Racket-related. The things you have listed seem to fall into two categories: you prefer Common Lisp, or things that have been done in Clamp.

I think I'd be happier about switching implementations if we could update the site that most people using the language use to communicate on! The instructions still say to get a specific old version of mzscheme!

-----

2 points by akkartik 297 days ago | link

Extremely valid point.

-----

4 points by akkartik 297 days ago | link

The only caveat I want to inject is to not blame Racket too strongly. Clamp showed me that I don't know enough CL to make a good Arc in it. By the same token, Pauan's https://github.com/arclanguage/arc-nu showed me how much better Arc-on-Racket can be. Racket is pretty mature, but the default Arc implementation hasn't moved much from the days of mzscheme.

-----

1 point by highCs 297 days ago | link

Sure, obviously Racket is a great language, specially for teaching. Though, I don't find it is in the same greatness category as C and python (and some others like Ruby, Rust and Go). Those are the hacker languages. I would like to see a lisp actually in this category.

-----

2 points by zck 347 days ago | link | parent | on: Passing values up the line

> I still need to check for reflections [if I already have (2 4 1 3), do not allow (3 1 4 2)].

There's a cool technique I read about to solve problems like this. I'll put it a few lines down in case you want to think about it yourself.

.

.

.

Sort them, then check for equality! I learned this when reading about anagrams.

-----

3 points by jsgrahamus 347 days ago | link

So if two results were (2 4 1 3) and (3 1 2 4), both of them sort to (1 2 3 4) so delete one of them? Of course all of the results will sort to (1 2 3 4) for a 4x4 board.

Not sure I understand.

-----

2 points by zck 346 days ago | link

Oh, you're right. I misunderstood what you meant by "reflections".

-----

More