If "a def redefines an inner," won't that still break whatever depended on that inner?
Maybe a def should shadow an inner? In my pursuits, I've been thinking about something vaguely like http://c2.com/cgi/wiki?HyperStaticGlobalEnvironment (which I got to from http://lambda-the-ultimate.org/node/3991), where definitions essentially replace the binding, leaving the previous binding intact for whatever closures captured it. I'd go farther than that: I'd have certain operations just replace the environment entirely by shadowing variables, etc., usually putting the old environment somewhere we can get to it again.
Also, in my mind closures in this hyper-static approach should automatically define any not-yet-defined free variable bindings they need as they're created. This approach requires the default kind of definition to be set!, so that the not-yet-defined bindings don't just get shadowed instead of defined. That means it's hardly a hyper-static philosophy at all; it's just an approach that use hyper-static capabilities where it needs to for namespacing (and in order to access them, there's likely to be boilerplate).
Sorry, this is sort of a ramble, I know. I don't have a lot of time right now to clean it up. ^_^;
Would that always work? It wouldn't let bar be defined before foo, which I still kinda care about. (http://arclanguage.org/item?id=12668) That's the problem with the hyperstatic idea as well (thanks for the link, btw.)
Or perhaps we should just have an explicit undef. Heh, I want to rename def back to defun just so undef is a rotation of defun.
But my problem still exits, how do I find out the story is a local post or a one with url.
You mean whether it's a topic with a URL and no text or a topic with text and no URL, right? Hmm, it looks like 'item-page is responsible for displaying the /item?id=... URL, and that calls 'display-item-text to display the textual content of the post. The implementation of 'display-item-text looks like this:
(def display-item-text (s user)
(when (and (cansee user s)
(in s!type 'story 'poll)
(blank s!url)
(~blank s!text))
(spacerow 2)
(row "" s!text)))
So it seems stories have both URLs and text internally, but the text is never displayed unless (blank s!url). That's probably the test you're looking for.
I could be wrong, but I think there's no widely adopted way to do those things, even in Anarki. I think most people just use a rather shallow directory structure and spell out (load "lib/something.arc") every time. Note that (load "...") resolves the path relative to Racket's (current-directory), which is usually the working directory Racket was started under. So typically people just start Racket from their Arc directory and don't bother messing with environment variables.
That doesn't mean it's a good situation here. :-p In particular, if someone ever wants to use multiple versions of the same library with the same Arc installation (loading them conditionally, maybe), I think the library'll need to be internally location-agnostic; you can't just put both versions in the same directory, after all. ^_^
So in Lathe I go to some trouble to make an alternative 'load function, 'loadrel, just so I can keep track of the current directory. It uses a global variable, 'load-dir* , to keep track of the current file's directory, and that variable is maintained by the functions 'loadrel and 'loadfromwd ("load from working directory," merely a 'load-dir* aware version of Arc's regular 'load).
If you want to try out my code, the necessary definitions are 'loadval from arc/modules/modulemisc.arc and 'split-at-dir, 'normalize-path, 'load-dir* , 'loadfromwd, and 'loadrel from arc/modules/path.arc. It's probably easier just to load the whole Lathe module system, which 'loadrel is a part of:
If you're going to implement something like this yourself, I recommend dropping to Racket and using Racket paths to avoid the trouble of things like my 'normalize-path. For a more comprehensive treatment, maybe someone could patch 'load to interact with Racket's 'current-load-relative-directory? Would that even make sense?
I haven't even managed to get out to local Meetup groups I'm signed up for, so probably nowhere. If there's a small miracle, I could probably go anywhere in the Silicon Valley, but anywhere else would take a bigger miracle. ^_^
2. What presentations would you like to hear?
Whatever there happen to be, really. I suppose I'm most interested in ways people think Arc could be improved from the ground up. Between Semi-Arc and the custom Arcs of aw and akkartik, there's been a lot of that kind of thinking around here lately.
3. Is there anything you would like to present?
Ooh, I'd probably do a talk about useful Arc design patterns I've found that seem to be too succinct to fit into the "build a macro for it" zone. I don't know how far that would take me, though. ^_^ So then I'd talk about various projects I'd done, I suppose.
4. Does it have to be any particular time of the year for you to be able to attend?
The time probably doesn't matter for me, just 'cause I'm unlikely to attend. Weekends would be more accommodating though. :-p
5. Any additional comments are welcome too, of course.
IMO, we tend to communicate pretty freely on this forum. If it's not enough, how about IRC or something?
arc> (obj a 1 b 2)
#hash((a . 1) (b . 2))
arc>
(let list list:list
(obj a 1 b 2))
#hash((((a 1 . nil) . nil) . ((b 2 . nil) . nil)))
Currently, (obj a 1 b 2) expands into (listtab (list (list 'a 1) (list 'b 2))), which means it uses the local meanings of 'listtab and 'list during evaluation.* The Arc community already removes much of the need for hygiene by following the convention of using (uniq) for local variable names generated by macros, but that doesn't help in this case.
Technically, we could fix this as a community too, as long as we adopt a convention like one of these:
- Have (obj a 1 b 2) expand into ('#<procedure: listtab> ('#<procedure: list> ('#<procedure: list> 'a 1) ('#<procedure: list> 'b 2))), for instance.
- Have (obj a 1 b 2) expand into (eval!listtab (eval!list (eval!list 'a 1) (eval!list 'b 2))), for instance, and avoid using "eval" as a local variable name.
- Avoid using existing global variable names as local variable names, and vice versa.
Whenever possible, I like being able to repair a REPL session just by fixing one buggy global binding, so I don't recommend the first option here. The third option is closest to what we have in practice, but I don't like the way the global/local distinction is hazy without introducing some kind of boilerplate naming convention. So the second option is kind of my favorite, but it still smacks of namespace qualification, and it doesn't help Arc code that already exists.
Semi-Arc takes a "none of the above" approach and just implements the hygiene, despite the incompatibilities that risks. I've only found one positive use of "free symbol capture" in practice,* so that probably won't be the top issue when porting code to Semi-Arc.
* IIRC, an example I wrote had one macro that bound a gensym-named local variable and another macro that referred to it using the same gensym. The second macro referred to the variable plainly enough that it was no more useful than an anaphoric variable, and it could just as well be replaced with a dynamic variable or a global variable. Nevertheless, it may turn out to be a useful technique for a variable that needs to be captured by lexical closures but only needs to be used for a specific purpose (incrementing it and broadcasting an update event, maybe).
I thought about using the same pattern in the Jarc sql package to dynamically turn tracing of the SQL statements on and off. But it seemed inelegant making all the sql functions into macros just to get the dynamic tracing, so I decided to use thread-local variables instead in that case.
Yep. ^_^ I like to use the pattern `(... (',(fn () x)) ...) to refer to all kinds of values from within generated code. I think it was http://arclanguage.org/item?id=11612 that prodded me into doing this.
Usually ',x is enough, but (',(fn () x)) has the benefit that it preserves the identity of something that has mutable state. Racket copies many data structures if they appear as syntax, even inside 'quote forms, but lambdas are data structures that escape that wrath.
arc> (is is (eval `',is))
t
arc> (mac thunk body `(fn () ,@body))
#(tagged mac #<procedure: thunk>)
arc> (is thunk (eval `',thunk))
nil
arc> (is thunk (eval `(',thunk.thunk)))
t
arc> (= foo '(1 2 3))
(1 2 3)
arc> (is foo (eval `',foo))
nil
arc> (is foo (eval `(',thunk.foo)))
t
I think the copying happens at the moment the Racket (quote ...) form is compiled:
Welcome to Racket v5.0.1.
> (define vec (vector 'a 'b 'c))
> (vector-set! vec 1 'r)
> vec
'#(a r c)
> (eval `(define (get-vec) ',vec))
> (vector-set! (get-vec) 2 't)
vector-set!: expects type <mutable vector> as 1st argument, given: '#(a r c); other arguments were: 2 't
=== context ===
C:\Program Files\Racket\collects\racket\private\misc.rkt:74:7
> (eq? (get-vec) (get-vec))
#t
> (eq? (get-vec) (eval `',(get-vec)))
#f
> (eq? (get-vec) (eval `(',get-vec)))
#t
If you want to work around this in your version of Arc, you can probably just have 'ac generate ((quote <procedure-returning-x>)) wherever it would normally generate (quote <x>). ^_^
Depending on the rest of your code, quasiquotation may need changes too. Maybe `(1 ,x 3) should compile to ((quote #<cons>) 1 ((quote #<cons>) value-of-x ((quote <procedure-returning-(3)>))))? If you're using fallintothis's code, this is probably relatively easy to accomplish.
If you don't work around Racket's copying, that's fine too. :-p
Awesome. If I had way more time on my hands, I'd have Lathe do bug-sniffing and provide a (version) function myself. :-p
I think feature-sniffing is usually the way to go, rather than implementation-sniffing, but making it possible to do implementation-sniffing too is still a net gain in convenience for an independent hacker. ^_^
I'll be sure to look at Jarc 21 eventually, but I'm sort of falling behind thanks to, well, getting a job. XD I'm behind on trying out Rainbow and Semi-Arc too, so this is one more for the to-do list. ^_^;
I definitely appreciate the dynamic proxy support though. I'll see how easy it is to incorporate that into Lathe's jvm.arc... sooner or later.
161 days ago you announced your jvm.arc? Interesting. Seems useful.
So Groovy allows dynamic classes, not just interfaces? I'd like to do that in Jarc also. But I don't see how to do it without generating byte code. Jarc now includes Jasmin (a JVM assembler) so generating byte code is pretty straight-forward.
Sun's implementation of JDK 6 is co-bundled with the Mozilla Rhino based JavaScript script engine. (...)
Rhino's JavaAdapter has been removed. JavaAdapter is the feature by which a Java class can be extended by JavaScript and Java interfaces may be implemented by JavaScript. This feature also requires a class generation library. We have replaced Rhino's JavaAdapter with Sun's implementation of the JavaAdapter. In Sun implementation, only a single Java interface may be implemented by a JavaScript object.
In other words, the Rhino distributed with JDK 6 provides no JavaAdapter functionality the Proxy class can't already achieve....
IMO, the cleanest way to handle nil is for it to be a separate type and for 'car and 'cdr to be generic (or at least ad-hoc generic), defined for the nil type as well as the cons type. This way, when extending a generic function, you don't have to put the empty list behavior and the symbol behavior in the same branch (which would make it harder for a programmer to extend a list function for symbols or vice versa).
Hmm, it sounds like that's what you had before waterhouse's input. :-p
In Lathe's generic/inheritance utilities (orc/orc.arc and orc/oiter.arc), I base the inheritance graph on a new type function, 'otype, mainly so that I can have a different type for nil. Because of the inheritance system, I also get to have a list type that both the nil type and the cons type inherit from, so that I can extend every list case in a single branch.
As for (coerce nil 'cons), I think that's the wrong API. It should shave some tokens to become listify.nil, and it shouldn't raise an error. Who really needs to coerce things into nonempty lists? ^_^
Hmm, it sounds like that's what you had before waterhouse's input. :-p
:) I think I still have that behavior. All I did was to fix coerce and 'nil. You can defgeneric without the acons check and defmethod on nil (or vice versa). It feels more 'pure', but I don't have any examples where it's a big win. It's _truly_ a win that you can simply replace def with defgeneric and get a superset of behavior without losing compatibility.
Well, besides the obvious difference that '+ works for numbers and strings.
I'm surprised that join doesn't work for strings. The heading "Using + to concatenate sequences is a lose" suggested to me that the alternative (join) would work for all sequences, not just lists.
That's a good point. However, when a function like 'string concatenates strings like 'join concatenates lists, it's most consistent for (string) to be "", right? You can't have (join) return "" as long as it returns nil, unless you also make nil and "" the same value.
Now, I'd trade bits of consistency for the sake of significant convenience, but I don't think there's significant convenience at stake here. I never use 'join or 'string for concatenation in a place I couldn't use + nil or + "", which are just as convenient. If we did that instead, we'd have a smaller vocabulary with less room for second-guessing the design. So IMO, 'join may well be useless, and the main value of 'string is that, when used with one argument, it plays well with ssyntax and 'map.