[Openmcl-devel] multiple read-time conditionals, puzzlement

Arthur Cater arthur.cater at ucd.ie
Mon Mar 13 15:05:46 PDT 2023


Thank you for that thorough explanation, I appreciate it.
Permit me to make a minor correction, I believe in the “:FOO not in” part, step 2, you mean evaluate feature expression to false. 

fwiw I’d hate to find in code (even my own) anything more complex than that doubled-up test of the same feature expression. I was experimenting because
(a) it was the first time I’d seen such a construction and I wasn’t sure it would do what it was clearly intended to do. I thought it was neat.
(b) I was just curious about what such syntax would mean in a mixed case.

Arthur

> On 13 Mar 2023, at 21:30, phoebe Goldman <phoebe at goldman-tribe.org> wrote:
> 
> 2.4.8.17 Sharpsign Plus, http://www.lispworks.com/documentation/HyperSpec/Body/02_dhq.htm <http://www.lispworks.com/documentation/HyperSpec/Body/02_dhq.htm> , says:
> 
>> #+ operates by first reading the feature expression and then skipping over the form if the feature expression fails. While reading the test, the current package is the KEYWORD package. Skipping over the form is accomplished by binding *read-suppress* to true and then calling read.
> 
> 
> This means that a series of #+ or #- read-conditionals will result in recursive calls to READ with a stack of T bindings on *READ-SUPPRESS*. Note that neither reader macro ever binds *READ-SUPPRESS* to NIL, only either introduces a binding of T or uses the existing value.
> 
> Assume that *READ-SUPPRESS* is globally NIL. Consider reading:
> 
> #+foo #+foo a b
> 
> If :FOO is in *FEATURES*, the reader will:
> 
> 1. Read the first #+FOO, evaluate its feature expression to true, and call READ recursively with no new *READ-SUPPRESS* binding.
>   2. Read the second #+FOO, evaluate its feature expression to true, and call READ recursively with no new *READ-SUPPRESS* binding.
>     3. Read A with the root *READ-SUPPRESS* binding of NIL, and return the symbol A.
> 4. Your initial call to READ has now returned, but there's more input. Call READ again to get another object.
> 5. Read B the root *READ-SUPPRESS* binding of NIL, and return the symbol B.
> 
> If :FOO is not in *FEATURES*, the reader will:
> 
> 1. Read the first #+FOO, evaluate its feature expression to false, and call READ recursively with *READ-SUPPRESS* bound to T.
>   2. Within that binding, read the second #+FOO, evaluate its feature expression to true, and call READ recursively with an additional layer of *READ-SUPPRESS* = T binding.
>     3. Within both bindings, read A with *READ-SUPPRESS* true, and return nothing.
>   4. Within the outer binding, read A with *READ-SUPPRESS* true, and return nothing.
> 5. Your initial call to READ has now returned, and you didn't get anything.
> 
> When you're dealing with multiple distinct feature expressions which are not uniformly all true or false, the behavior gets more complicated, but it's always defined by the spec as recursive calls to READ with a stack of *READ-SUPPRESS* bindings. I haven't looked carefully at the cases that spawned this discussion to see if CCL's behavior is compliant, but I don't believe there's any ambiguity in the spec.
> 
> Cheers,
> phoebe
> 
>> On Mar 13, 2023, at 5:06 PM, Tim McNerney <mc at media.mit.edu> wrote:
>> 
>> Would someone mind quoting “chapter and verse”? 
>> 
>> Somehow, even those of us with decades of Common Lisp experience, all trying to follow the drama of the X3J13 committee, a bunch of us “missed the memo” about this convenient, allegedly legal, but “buyer beware” syntax. 
>> 
>> Yes, I absolutely hate 
>>      #+foo :keyword #+foo argument too. 
>> 
>> --Tim
>> 
>>> On Mar 13, 2023, at 14:00, Robert Goldman <rpgoldman at sift.info> wrote:
>>> 
>>>  On 13 Mar 2023, at 12:42, Ron Garret wrote:
>>> Oh, forgot to add...
>>> On Mar 13, 2023, at 10:20 AM, Arthur Cater <arthur.cater at ucd.ie> wrote:
>>> It never previously occurred to me that read time conditionals could be nested.
>>> Just because you can do something doesn't mean you should.
>>> rg
>>> I was surprised myself to see
>>> #+foo #+foo
>>> 
>>> used to make two s-expressions (in)visible in the presence (absence) of the :foo feature. But it's clearly dictated by the spec, and is often handy when, for example one might want to have something conditionally in a property list
>>> (list :prop1 12
>>> #+foo #+foo
>>> :foo 'bar)
>>> 
>>> In my opinion, that's clearer than
>>> (list :prop1 12
>>> #+foo :foo #+foo 'bar)
>>> 
>>> which obscures reading this as a property list and obscures the fact that the two elements of the list are going to be swapped in or out based on a single feature.
>>> (append (list :prop 12) #+foo (list :foo 'bar) )
>>> 
>>> is not an alternative particularly pleasing to me, but YMMV. It's certainly very busy.
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.clozure.com/pipermail/openmcl-devel/attachments/20230313/345ad28d/attachment.htm>


More information about the Openmcl-devel mailing list