I'm quite impressed, actually! In addition to the name (which in itself beats my (html (html problem), the quoting system seems smart. I'm going to have to mull this over more.
Another punctuation possibility I've considered that's different from both of these is quasi-quotation,
(tohtml ; another decent name
`(body
(h1 "Simple Math")
(p "1 plus 1 equals " ,(+ 1 1))
; would generate:
; <body><h1>Simple Math</h1><p>1 plus 1 equals 2</p></body>nil
which would seem like a very natural way to escape into Arc. Not only does it look better, but it could get me out of using 'eval in that 'htmlf function. In fact, the more I write about this, the better it sounds. I think I'll give quasi-quotation a shot.
are probably equivalent, though I don't know how quoting affects strings. Odds are the same system could handle both styles, which means that programmers could use whichever they prefer. Personally I like the 'tag notation for tags, but hopefully it would be flexible enough to handle both.
What's the current status of whtml.arc? I can't look at the repo right now. Does it look like something that could be used as is?
I haven't found whtml at http://github.com/nex3/arc/tree/master/lib/ yet. I did however just stumble upon sml.arc by akkartik, which appears to be super relevant to this discussion.
It looks like it's function based and works on simple lists, so it would probably be conducive to the quasiquote form of escaping to arc. Anything seem to be missing from sml.arc that you wanted in your new version? Personally I think the interface could use some work, but that's about it.
Hmm. I'll have to see if I can find it elsewhere. I guess that w/html must have been a macro that bent quotes to its own purpose, whereas marcup or your 'tohtml merely take lists as input.
sml.arc sounds familiar; I vaguely remember someone else going through a discussion similar to ours, in which SXML was also mentioned.
> Also, why are some of your expressions wrapped in an extra layer of parens? i.e. ((script src "arc.js")). Is this so that you can differentiate the body vs attributes?
Yes, exactly. I can see now that they're using the @ symbol to differentiate attribute lists, but it's interesting to note that they actually end up using more parens. Unless I've misunderstood, where my program would have
In light of this, could you elaborate on your recommendation to adopt SXML's syntax? Do you find it somehow superior or does it have more to do with adopting a standard?
> For the (html (html issue, I would consider instead making a more general 'sxml macro, and then several helper macros such as 'html which automatically generate boilerplate doctypes, etc.
Sounds like a wise path of generalization to carry out over the long run.
You're right, I hadn't noticed how many parens SXML actually uses. I guess I just preferred more of a tree style "tag owns attributes" than the idea of applying a tag to its body.
I originally like the idea of the standard, but SXML probably supports far more than we need for now. How about a compromise?
This uses arc's style of "leave out parens for grouping pairs" like you were doing, but also doesn't require the attribute parens if you don't have attributes. This seems to make the tag style more homogeneous.
The body can be distinguished from the attribute-value pairs thanks to either the fact that it doesn't begin with a symbol or the fact that there's nothing to pair it with.
It does save a single pair of parentheses every once in a while, but it takes half a page of comments to explain comprehensively. :-p Then again, it's meant for Arc macros in general, so some of the idiosyncracies might disappear if it's modified for a specific purpose like this one.
Do y'all like the x:a?
I thought the "x:a" was just an abbreviation for things like "w/html:a", "html:a", "tohtml:a", and "sml:a", substituting whatever you decided the macro name would be. What alternative are you thinking about?
> I thought the "x:a" was just an abbreviation for things like "w/html:a", "html:a", "tohtml:a", and "sml:a", substituting whatever you decided the macro name would be.
The "x:a" originally came from the example at http://en.wikipedia.org/wiki/SXML#Example, where I think it had another meaning - maybe something to do with XHTML... anyway, it's probably not important. You clarified that I wasn't missing something in the conversation (unless we both are ;).
> This uses arc's style of "leave out parens for grouping pairs" like you were doing, but also doesn't require the attribute parens if you don't have attributes.
I like that compromise and will definitely consider it. To be sure though, my current implementation doesn't require the attribute parens for nil attributes either:
On these cases, my html.arc and the compromise converge. It's for the non-nil attributes case that they differ, and I think it comes down which you dislike less: the tag name in the caar position or the @ symbols.
Yes, but your current method seems to lack consistency (at least to me).
In some cases, (script fn "somefn();") means script with attributes, in others it means that it has a body. The difference is where the (script ...) is located; at the car of a list or not. Personally, I like the consistency provided by "anything that's not an @ list is body" which means that you don't have to pay as much attention to the number and layering of parens.
How would using ampersand over dot make macro writing much easier? Is it just that you find the notation more intuitive, or is there something else?
Personally I prefer the dot because I think it looks less jarring and there's the connection with improper lists, as pg mentions in the tutorial (http://ycombinator.com/arc/tut.txt):
(These conventions are not as random as they seem. The parameter
list mirrors the form of the arguments, and a list terminated by
something other than nil is represented as e.g. (a b . c).)
So your real question is why dots don't work in quasiquote, and what should be done to fix them. That's a question that we can relate to a lot better than what we originally thought was "I don't like dots"
Would someone mind being more explicit about how it doesn't work? After dotting the outer definition's rest parameter as well so that the first line reads,
"It's alive." is just a tongue-in-cheek message printed by default to the root page (probably http://localhost:8080/) of a running instance of the Arc server. You can see where it comes from if you open the file srv.arc in your arc directory and look for the line:
(defop || req (pr "It's alive."))
The || from that is a symbol for empty, so just as your (defop hello ...) command puts a page at http://localhost:8080/hello, (defop || ...) puts a page at http://localhost:8080/. (Nothing comes after that final slash since we used the empty symbol instead of "hello".) You could replace the default "It's alive." message by running a command like
(defop || req (pr "jsgrahamus rox!"))
at the REPL.
Were you able to get this stuff working, by the way, or are you still stuck??
> My other question is I would like to be able to search the forum. How can I do that?
The lack of an onsite search bar is a frequent question/criticism here as well as on Hacker News. Offsite, Search Arc Forum [http://af.searchyc.com/] nicely provides the functionality. Querying Google with the format
It might be more elegant to take advantage of s-expressions for this, as in
(module mylib
(def func-a ...))
and
(w/module mylib
(func-a ...))
rather than having imperative declarations that apply to an entire file.
Thinking about module/namespace systems in general, I guess as long as definitions are still global by default then they shouldn't bother anyone who doesn't want them. You might also be interested in aw's piece on library dependencies: http://awwx.ws/thinking-about-dependencies
With closures and 'deftem together, I haven't yet had the need for much more of an object system in Arc. These templates are great because they're so transparent, though I guess I've sometimes wished they were more robust (e.g. http://arclanguage.org/item?id=11855).
What do you like about having an object system, specifically? I wouldn't mind having one too, but I think object systems get complicated and arbitrary very quickly. I'd rather not have one monolithic abstraction where several highly-focused ones would do.
I do find myself switching to Groovy a lot thanks to its object system. I think what I mainly like is the ability to make an instance of FooSubclass and automatically have "foo in FooSuperclass" and "foo in FooInterface" be true.
Using Arc's built-in notion that the type of an object is the result of calling the 'type function on it (which is configurable via 'annotate), it's easy enough to achieve a form of inheritance that accomplishes what I just described:
; This is a table from type symbols to lists of their supertypes.
; Indirect supertypes are included in these lists, but no type is a
; member of its own list. There are no inheritance loops, either;
; inheritance here is a directed acyclic graph, and this is the
; transitive closure of that graph.
(= indirect-inheritance* (table))
(def inherits (subtype supertype)
(~~mem supertype (cons subtype indirect-inheritance*.subtype)))
(def fn-def-inherits (subtype . supertypes)
(each supertype supertypes
(when (~inherits subtype supertype)
(when (inherits supertype subtype)
(err "There was an inheritance loop."))
(let supers (cons supertype indirect-inheritance*.supertype)
(zap [union is supers _] indirect-inheritance*.subtype)
(each (k v) indirect-inheritance*
(when (mem subtype v)
(zap [union is supers _] indirect-inheritance*.k)))))))
(mac def-inherits (subtype . supertypes)
`(fn-def-inherits ',subtype ,@(map [do `',_] supertypes)))
(def isinstance (x test-type)
(inherits type.x test-type))
(def a- (test-type)
[isinstance _ test-type])
Come to think of it, I can't think of anything else object-oriented I miss in Arc. (OO is good for dispatch too, but I've already made an Arc dispatch library I like better.) I'll make sure to try this out the next time I program something substantial in Arc.
So, I've talked a lot about me, but my question to you still stands. What features are you looking for in an object system?
The most important feature of object oriented is name compressing.
Imagine a program with a lot of different databases.
Now you have to give names for functions that add element,
You will have to give them names like:
That sounds like dispatch to me. ^_^ You'd like to use one name but give it multiple meanings based on the types involved. This thread (http://arclanguage.org/item?id=11779) has a couple of approaches to dispatch from akkartik and myself.
Hmm, I've been having trouble for a while, trying to figure out my favorite way to have inheritance and multiple dispatch at the same time. (Single dispatch with inheritance seems more straightforward, but I'd rather not bother with it if I could use multiple dispatch instead.) If one method signature is (A, B) -> C, and another is (B, A) -> C, and A is a subtype of B, then what happens if you call the method with (a, a)? That could just cause an error, or the first argument could take precedence, but I'm not sure which approach I like better.
I think that multi dispatch is good idea for strong type languages.
If c++ encounters this problem it will solve it at
compile time (I think it will try to find the solution that
is best for the first variable then the second and so on).
For a dynamic language like arc multi dispatch
will have an efficiency cost. In my own opinion:
It is one of the "too smart to be useful" features of
common lisp. It is one of the reason people hate clos.
I have a question for you:
In what way a multi dispath is better then the alternatives?
You can dispatch only on the first argument
or hold a virtual table of functions for every object.
For a dynamic language like arc multi dispatch will have an efficiency cost.
I don't think the efficiency cost for dynamic dispatch on the first argument would be significantly different, and I'm not worried about either one. I think they're at worst as inefficient as a sequence of if statements, which is to say they would take constant time (given a constant number of methods to check and constant time for each check).
Constant time can still be painful in the right quantity, and making the decision at compile time would indeed help, but Arc doesn't have the necessary static type information to go on (as you know). So multiple dispatch and single dispatch alike have to suffer a bit.
It is one of the reasons people hate clos.
Well, I've heard nothing but good things about CLOS, but then I haven't heard that much. ^_^ Is there some good anti-CLOS reading material you can recommend? XD
In what way is multi dispatch better then the alternatives?
It's partly a matter of name compression. ^_-
; no dispatch
(collide-spaceship-with-spaceship s s)
(collide-spaceship-with-asteroid s a)
(collide-asteroid-with-spaceship a s)
(collide-asteroid-with-asteroid a a)
; single dispatch (on the first argument)
(collide-with-spaceship s s)
(collide-with-asteroid s a)
(collide-with-spaceship a s)
(collide-with-asteroid a a)
; double dispatch
(collide a s)
(collide s a)
(collide a s)
(collide a a)
Yeah, I stole Wikipedia's example here. Another example is a comparison function that needs to compare values of many different types. Yet another is a "write" function which has different behavior for each type of writer object and each type of object to be written.
When it comes right down to it, I just believe multiple dispatch ought to be a simpler concept than single dispatch, since it imposes fewer restrictions on the programmer. Unfortunately, it seems to replace one arbitrary restriction with a bunch of (what I see as) arbitrary design decisions. ^_^;
For every one of your examples,
we can use double dispatch design pattern;
For example:
(collide o1 o2) call
(collide-with-spaceship o2 o1) if o1 is a spaceship
or (collide-with-asteroid o2 o1) if o1 is an asteroid.
I think that you can even abstract this design pattern
with a macro (but I did not try it).
So you still did not convince me that multi dispatch is
a good feature.
> Arc need all the basic features for some one to take it seriously.
As long as implementing any feature for the now doesn't compromise Arc's quality in the long term, I doubt anyone here would disagree with you. Keep in mind though that Arc's core language is still subject to change (http://www.paulgraham.com/core.html).
Thank you for the feedback and for fixing 'join! ^_^
> Also, note that if you're going to define your own version of falsity (no()), then the JavaScript && and || aren't necessarily going to play along with that. They'll treat "" as false, for instance.
Glad you pointed this out, may save me some debugging time. :)
Speaking of creating new structures vs. using built-in ones, I have considered switching to fake conses. That is, instead of there being a separate cons object as there is now, cons, car, cdr etc. would be array manipulations that make JavaScript arrays act just (or almost) like Arc lists. Do you have an opinion on this?
Re: 'if, the current version might seem more intuitive to a JavaScripter, but your approach may be more consistent with the way I'm expanding 'do. And then there's your point, that the latter has a close 1-to-1 correspondence of expressions with Arc while the former breaks up an expression into several statements. (Is this what you meant, or have I misunderstood?)
> As far as nested strings go, could you elaborate on that?
In the first Arc Challenge attempt I posted is the line,
(+ |\'you said: \'| foo.value)))))
The |\'you said: \'| from that is manual string escaping I'm doing because 'js naively compiles "you said: " to 'you said: ' without considering the need for backslashes. I think it's important to be able to have JavaScript within HTML within JavaScript within HTML within ... within JavaScript, and I'm not sure it's a particularly difficult string escaping problem - I just haven't gotten it working yet.
...array manipulations that make JavaScript arrays act just (or almost) like Arc lists. Do you have an opinion on this?
Well, to have cons produce an JavaScript array would be a bit odd. What happens to improper lists? (Well, Arc chokes on improper lists all the time, so maybe it doesn't matter. :-p )
I think it could be a good long-term idea to support both JavaScript arrays and the Arc cons type you already have. Functions like 'all, 'map, and 'join could work for both kinds of lists, and this way people wouldn't necessarily have to change the way they're using conses, and they could work closer to the metal (or whatever JS is ^_^ ) when that was more useful.
...the latter has a close 1-to-1 correspondence of expressions with Arc while the former breaks up an expression into several statements. (Is this what you meant, or have I misunderstood?)
I'm mostly just concerned that you should be able to say things like (let x (if (< foo 2) 0 foo) (* x x)). If (if ...) translates to a statement, that won't work.
|\'you said: \'|
Oh, I see now.
Yeah, the string escaping shouldn't be that difficult. I suppose the trickiest part about string escaping is remembering to do it. ^_^
Thanks. I have looked at ParenScript, but not as extensively as I probably should. Have you used it, or is there any aspect of their approach you might particularly recommend?
Thanks, it works now. (And thanks for the link to Scheme2js!)
I installed ParenScript, but haven't used it for anything.
I recommend it for having a community that actually uses it for production, and for being around long enough to have tried a variety of different approaches to hosting a lisp on top of JavaScript. It's probably worth reading through their mailing list archives to see how they've evolved.
I also recommend coffee-script, which is sort of a python/ruby syntax for Javascript. Probably the most inspiring idea from coffee-script is that the language is self-hosted (it was initially cross-compiled from ruby, but is now written in itself.)
I have looked at parenscript and even started an arcscript which is totally non-functional - I was just translating it to Arc as I went as a way to understand the original codebase. I never finished it, but I'll post what I have on github and maybe we can collaborate.