Arc Forumnew | comments | leaders | submitlogin
2 points by waterhouse 4904 days ago | link | parent

[By now other replies make this somewhat redundant, but I'll proceed anyway. Much this post is rambling about types and language design.] I think dido's question can be answered more simply than that. I.e.: (1) nil is 'nil, always; (cons 'a (cons 'nil nil)) = (cons 'a (cons nil nil)). (2) The funny behavior you observe stems from this: The "coerce" function (and also the "string" function, which uses "coerce" quite directly) coerces the symbol 'nil to the empty string. This decision was made for convenience, as aw illustrates here: http://arclanguage.org/item?id=10802

To answer your question: It's more like a decision to make nil evaluate to 'nil. The train of reasoning goes like this:

1. We need a single value to be considered "false"--by the "if" special form and by any function that's supposed to return either true or false. We call this value nil. Now, we could invent a new type for nil (maybe a "false" type, or maybe a "boolean" type that is either true or false), but in Arc (and Common Lisp before Arc, and probably several other Lisps both historical and contemporary), nil is a symbol.[1]

2. You could stop here. Use 'nil whenever you want to return false. But it's kind of annoying to remember to type the quote. So, instead, we bind the global variable nil to the value 'nil. (The compiler actually handles nil directly--if you managed to rebind nil, it wouldn't make a difference, because nils are transformed away anyway.) Likewise, t is bound to 't, the canonical true value.

[1] Actually, in Common Lisp, nil has type "null", which is a subtype of "symbol", in the same way that a string is a subtype of an array. This might be worth considering...

  * (type-of nil) ;Common Lisp
  NULL
  * (symbolp nil)
  T
  * (type-of "ach")
  (SIMPLE-ARRAY CHARACTER (3))
  * (arrayp "ach")
  T
  * (stringp "ach")
  T
Additionally, in CL, the type of t is "boolean", also a subtype of "symbol". And, in fact, "null" is a subtype of "boolean". Hmmph. I feel that's a bit excessive. At any rate, it doesn't make much difference (you could always just ask (is x t)), except perhaps when you're giving type advice to the compiler--but if you were doing that, you should be able to define a "boolean" type as (or t nil), the way you'd define any other derived type. Perhaps nil should have a slightly special type, as it's treated specially by the primitives "if", "car", "cdr". [And hmm, could conses be fundamentally vectors of length 2, just with a different type tag? Probably. This is of course far afield of your question.]

Methinks "is-a" type semantics are fundamental for the implementation. Every object is some number of bits laid out in memory. Hmm, but then (listening to the part of my brain that generates objections anytime I talk as though I'm sure), there are things that could be represented in one of many ways, any of which might be best in a given situation. SICP gives the example of complex numbers as rectangular vs polar, and polynomials could be represented as lists or vectors of coefficients, alists or hash tables of (power coefficient), perhaps in factored form if applicable, and so on. (Even in my nil example, it could be a cons cell or a symbol.) Might it be bad, might it make it particularly difficult or inefficient to do that kind of abstract type behavior if the implementation just uses "is-a" semantics? Ehhh... no. :-) Type dispatching will be the answer, and it'll be just as easy/difficult either way.

[Comment: Any question of making objects callable in functional position is an efficiency concern. If you didn't care about efficiency, then you could just wrap every object inside a closure, and write the system's "print" and "type" functions and so forth to ask the closure how to properly print or type the object. ... And back to conses-as-vectors: I think you might want some arrays to have an entire field of tagging information that would probably need to be stored in the array. At the very least, you'd want the length. And I wouldn't want to make all cons cells 50% bigger. So, eh, conses will be special, and perhaps one could include boxes too... and maybe there's something to "weak" references, which exist but which the garbage collector is free to destroy. Actually, those could be implemented with boxes, though at the cost of adding an indirection to normal references to that object. Mmm.]



2 points by rocketnia 4904 days ago | link

"This decision was made for convenience, as aw illustrates here: http://arclanguage.org/item?id=10802 "

"Conditionally include things in a string"

Sorry if I enter into a bit of drama here.... I don't have anything against you or aw, but every time I see that comment, something nags at me. :)

At the time, there were about six reasons I didn't respond to that comment (which was a reply to a comment of mine):

1) I didn't consider it to be a "brilliant use," since the workaround without it would be negligible:

  (string "You are going "
          (if (> speed 100) "very " "")
          "fast")
2) Were I to have accepted the brilliance of this use case, I'd only have been more interested in why 'pr didn't have the same behavior (which was my main gripe to begin with):

  arc> (= speed 2)
  2
  arc> (prn "You are going " (if (> speed 100) "very ") "fast")
  You are going nilfast
  "You are going "
3) It was actually something I had already thought of and cast aside for the above reasons. (So it didn't even qualify as something "I'm not thinking of.") If aw was grasping for straws like I was, there probably wasn't much more point in talking about it.

4) It had upvotes too--at least one upvote at the time I first read it. Apparently, what I thought was common sense would be outnumbered.

5) I hadn't programmed in Arc that much yet. Maybe the upvoter(s) saw something there I didn't. At any rate, I'd probably be able to discuss the pros and cons better once I'd used Arc for a while.

6) I did say "I can't think of a single time," and this was a single example. I kinda decided to eat my words on account of that. :-p

Turns out (string:accum ...) is the use case I found that convinced me. The key point was that 'string wasn't consistent for symbols because it was too busy being consistent for lists.

-----

1 point by aw 4902 days ago | link

Just to be clear :-), I wasn't advocating for the behavior, merely answering the question if was there any use for it ^_^

-----

1 point by rocketnia 4902 days ago | link

Thanks for not taking that too harshly. XD

-----

1 point by rocketnia 4904 days ago | link

"conses-as-vectors"

My stance is that they're intuitively separate things. If you take the length of a vector of length 2, you get 2. If you take the length of a linked list node, that's a different story. Still, if a linked list node is implemented as a wrapper around a vector, that's fine.

-----