From: Vassil Nikolov
Subject: eof-error-p/eof-value
Date: 
Message-ID: <l03130300b3c8eeb83e89@195.138.129.84>
Assume I design a function of my own that is similar to READ in the
sense that it consumes a datum off a source and either raises an
exception or returns a special value on end of data depending on
additional arguments.  It is thinkable that, instead of having two
separate arguments for that, I use just one optional argument,
and its presence or absence controls whether an error is signalled.
I.e. the lambda list is ``source &OPTIONAL (eod-value 'NIL not-eod-error-p)''
rather than ``source &OPTIONAL (eod-error-p 'T) eod-value'' (where
`eod' means `end of data').

Is there a pitfall with this approach?


Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.





 Sent via Deja.com http://www.deja.com/
 Share what you know. Learn what you don't.

From: Kent M Pitman
Subject: Re: eof-error-p/eof-value
Date: 
Message-ID: <sfwzp0cr4y7.fsf@world.std.com>
Vassil Nikolov <········@poboxes.com> writes:

> Assume I design a function of my own that is similar to READ in the
> sense that it consumes a datum off a source and either raises an
> exception or returns a special value on end of data depending on
> additional arguments.  It is thinkable that, instead of having two
> separate arguments for that, I use just one optional argument,
> and its presence or absence controls whether an error is signalled.
> I.e. the lambda list is ``source &OPTIONAL (eod-value 'NIL not-eod-error-p)''
> rather than ``source &OPTIONAL (eod-error-p 'T) eod-value'' (where
> `eod' means `end of data').
> 
> Is there a pitfall with this approach?

There are two options:

(1) If the parameter info controls what value to return on eof, there 
    have to be two parameters (an eof-error-p and an eof-value) 
    OR ELSE there has to be a privileged value which cannot
    be the magic return value.  (That's why there are two arguments; to
    allow full generality of return values.)

(2) It's true that you can use one value (or none) if you plan to signal.
    None if either you always want an error OR if you want to signal a
    non-fatal condition that if uncaught goes ignored. (Might lead to
    infinite loops or other bad behavior, but is theoretically ok.)

The reason (1) is somewhat preferrable to (2) in some cases is that, at
least in principle, (1) is more bounded in both space and time;  The
behavior is directly known at the time it matters without further effort.
In (2), the callee [your new reader] has to cons an error object to signal;
it's not dynamic extent.  And then it has to do the signalling process
(which takes an undetermined amount of time--usually small, but bounded only
by circumstance, and certainly slower than what (1) is doing).  Further, 
even electing a restart takes more overhead than (1).

The real issue is this:  the condition system has a certain overhead but
accomodates those cases for which the handshake is with an unknown party
who has an unknown amount of information.  That's not really the case here.
You know pretty much exactly who has the information you want, and if you
don't provide a way for them to pass you just exactly tht information, you're
inviting overhead that is unnecessary. I'd rank this on the same basic par
as doing a THROW or a RESTART-BIND in a program just to implement what
you could do with BLOCK/RETURN or TAGBODY/GO.  The latter two are efficient
means designed for places where you can "dead reckon" both ends of the
communication.  The former two are general purpose things that contain 
provisions for advertising, search, etc.

Of course, if there is a privileged value for your reader, the compromise
is just to use that value and one parameter.

Btw, this same issue of efficiency is commonly cited in floating point.
EVEN IF there were a way to catch floating point errors (well, there's a
"way" but the particular classes are not well-defined in portable CL,
so you can't use it without being implementation-dependent), what a lot
of people want is a way to tell the implemenation "don't signal them".
It's too important they be fast, and so something like a
 (WITHOUT-FLOATING-POINT-TRAPS ...)
is better where the implementation (down to sometimes even the hardware)
has a special ability to head off the general mechanism which isn't really
needed in that case and where you can predict that fact with reliability
at program design time.
From: Vassil Nikolov
Subject: Re: eof-error-p/eof-value
Date: 
Message-ID: <l03130303b3c9049c6363@195.138.129.81>
Kent M Pitman wrote:                [1999-07-31 19:32 +0000]

  > Vassil Nikolov <········@poboxes.com> writes:
  > 
  > > Assume I design a function of my own that is similar to READ in the
  > > sense that it consumes a datum off a source and either raises an
  > > exception or returns a special value on end of data depending on
  > > additional arguments.  It is thinkable that, instead of having two
  > > separate arguments for that, I use just one optional argument,
  > > and its presence or absence controls whether an error is signalled.
  > > I.e. the lambda list is ``source &OPTIONAL (eod-value 'NIL not-eod-error-p)''
  > > rather than ``source &OPTIONAL (eod-error-p 'T) eod-value'' (where
  > > `eod' means `end of data').
  > > 
  > > Is there a pitfall with this approach?
  > 
  > There are two options:
  > 
  > (1) If the parameter info controls what value to return on eof, there 
  >     have to be two parameters (an eof-error-p and an eof-value) 
  >     OR ELSE there has to be a privileged value which cannot
  >     be the magic return value.  (That's why there are two arguments; to
  >     allow full generality of return values.)
  > 
  > (2) It's true that you can use one value (or none) if you plan to signal.
  >     None if either you always want an error OR if you want to signal a
  >     non-fatal condition that if uncaught goes ignored. (Might lead to
  >     infinite loops or other bad behavior, but is theoretically ok.)

I only now see that I asked my question somewhat sloppily.  I forgot to
emphasise that I assume that the eod-value argument will be the last
one.  (Well, one can never really assume such things, but this becomes
more acceptable if eod-value is a keyword argument.)  With READ,
one can't really merge eof-error-p and eof-value (unless, of course,
there is a privileged value, which is not very elegant) because one
might need also to supply the recursive-p argument.  But if it wasn't
for the latter, one would never have to supply eof-value when
eof-error-p was true, which led me to think that one could merge
them (using a supplied-p parameter), to simplify the calls---unless
this was a bad design decision for some non-obvious reason.

In other words, will the following way of doing it lose:

  (READ S) is like (MY-CONSUME S);
  ditto for (READ S T);
  (READ S NIL) is like (MY-CONSUME S NIL);
  (READ S NIL FOO) is like (MY-CONSUME S FOO);
  and the case of (READ S T NIL T) is not applicable for MY-CONSUME
  (note that this case is an idiom for (READ S :DEFAULT :DEFAULT T))

and the callee is roughly

  (defun my-consume (source &optional (eod-value 'nil not-eod-error-p))
    "Returns the next datum available from source."
    (cond
      (<more data available> <consume one and return it>)
      (not-eod-error-p eod-value)
      (t <raise exception>)))

  [...]

But in spite of asking my question in an inadequate way, I did receive
an interesting answer.  Thank you.


Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.





 Sent via Deja.com http://www.deja.com/
 Share what you know. Learn what you don't.
From: Pierre R. Mai
Subject: Re: eof-error-p/eof-value
Date: 
Message-ID: <873dy3fymv.fsf@orion.dent.isdn.cs.tu-berlin.de>
Vassil Nikolov <········@poboxes.com> writes:

> I only now see that I asked my question somewhat sloppily.  I forgot to
> emphasise that I assume that the eod-value argument will be the last
> one.  (Well, one can never really assume such things, but this becomes
> more acceptable if eod-value is a keyword argument.)  With READ,
> one can't really merge eof-error-p and eof-value (unless, of course,
> there is a privileged value, which is not very elegant) because one
> might need also to supply the recursive-p argument.  But if it wasn't
> for the latter, one would never have to supply eof-value when
> eof-error-p was true, which led me to think that one could merge
> them (using a supplied-p parameter), to simplify the calls---unless
> this was a bad design decision for some non-obvious reason.

I generally think that functions should allow me to pass the default
value of an optional argument explicitly.  I.e. for

(defun my-fun (a b c &optional (d nil d-p))
  ...)

I'd like 

(my-fun 1 2 3 nil)

to behave just as if I had called

(my-fun 1 2 3)

Bear in mind that not only users call functions, but that functions
might have to pass through arguments to a function, without looking
into them.  If you let the above two function calls behave differently,
the calling function would have to find out whether to call my-fun with
3 or 4 arguments, thereby violating abstraction barriers.

Using supplied-p to change the behaviour of functions seems only wise
for functions that are intended for the user only.

All just MHO, of course...

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Vassil Nikolov
Subject: Re: eof-error-p/eof-value
Date: 
Message-ID: <l03130301b3ca421e2270@195.138.129.79>
Pierre R. Mai wrote:                [1999-08-01 14:56 +0200]

  > I generally think that functions should allow me to pass the default
  > value of an optional argument explicitly.  I.e. for
  [...]
  > Using supplied-p to change the behaviour of functions seems only wise
  > for functions that are intended for the user only.

Yes, you are right.  Thank you.


Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.





 Sent via Deja.com http://www.deja.com/
 Share what you know. Learn what you don't.
From: Tim Bradshaw
Subject: Re: eof-error-p/eof-value
Date: 
Message-ID: <ey3yafwd21d.fsf@lostwithiel.tfeb.org>
* Vassil Nikolov wrote:
> Assume I design a function of my own that is similar to READ in the
> sense that it consumes a datum off a source and either raises an
> exception or returns a special value on end of data depending on
> additional arguments.  It is thinkable that, instead of having two
> separate arguments for that, I use just one optional argument,
> and its presence or absence controls whether an error is signalled.
> I.e. the lambda list is ``source &OPTIONAL (eod-value 'NIL not-eod-error-p)''
> rather than ``source &OPTIONAL (eod-error-p 'T) eod-value'' (where
> `eod' means `end of data').

I think that kind of works but it's appallingly difficult to use.  If
I understand you, your are using the supplied-p feature to
distinguish between:

	(foo blarble)	; signal error on EOD

	(foo blarble nil) ; return NIL on EOD
	
	(foo blarble 'EOD) ; return EOD on OED

I think that would *work*, but it's a terrible design, because in lots
of cases you now have to have a little switch in the caller:

	(if want-error-p
	   (foo blarble)
	   (foo blarble nil))

rather than:

	   (foo blarble want-error-p)

Also I have no idea if supplied-p parameters are supported in other
Lisps, though that may not be a big issue.

--tim
From: Vassil Nikolov
Subject: Re: eof-error-p/eof-value
Date: 
Message-ID: <l03130305b3c9d12236b5@195.138.129.79>
(Thanks to Kent Pitman for responding to Tim Bradshaw, otherwise I
wouldn't have seen the latter's post as it did not show up on the
server I use for reading.  Usenet works in strange ways sometimes;
I so much wish I had access to the `true definitive' NNTP server for
comp.lang.lisp (note that Deja does not qualify as a _NNTP_ server).)

Kent M Pitman wrote:                [1999-08-01 07:12 +0000]

  > Tim Bradshaw <···@tfeb.org> writes:
  > 
  > > I think that kind of works but it's appallingly difficult to use.  If
  > > I understand you, your are using the supplied-p feature to
  > > distinguish between:
  > > 
  > > 	(foo blarble)	; signal error on EOD
  > > 
  > > 	(foo blarble nil) ; return NIL on EOD
  > > 	
  > > 	(foo blarble 'EOD) ; return EOD on OED

Yes, this is exactly what I had in mind (and was unsure if it was
a good idea).

  > Ah, I read his message earlier and was struggling to understand the
  > relevance of the arg being last, but now I do.  Thanks for deciphering this.

I apologise for being so sloppy and obscure, two times in a row.

  > > I think that would *work*, but it's a terrible design, because in lots
  > > of cases you now have to have a little switch in the caller:
  > > 
  > > 	(if want-error-p
  > > 	   (foo blarble)
  > > 	   (foo blarble nil))
  > > 
  > > rather than:
  > > 
  > > 	   (foo blarble want-error-p)
  > 
  > Yes.  I use this supplied-p thing from time to time, but I almost
  > always regret it.  It definitely composes badly.

Thanks to both of you for this.  This is exactly what I needed; I had
some intuitive feeling that that design idea wasn't that great, but couldn't
figure out exactly why.

  > Further, there's a constant pressure to add args, and optionals
  > get less friendly as you add more of them.  I recommend starting out
  > with keywords, so you don't end up with a problem if you have to skip
  > over an optional.  Wanting to supply a later arg but having no way 
  > to talk about the middle arg being missing is a problem.

Yes, certainly.  I think I mentioned that actually keywords are
necessary to give this design at least a chance to be viable.  And
with compiler macros one can afford not to worry that much about
the potential inefficiencies of keywords.

  [...]



Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.





 Sent via Deja.com http://www.deja.com/
 Share what you know. Learn what you don't.
From: Pierre R. Mai
Subject: Re: eof-error-p/eof-value
Date: 
Message-ID: <87so63cc0o.fsf@orion.dent.isdn.cs.tu-berlin.de>
Vassil Nikolov <········@poboxes.com> writes:

> (Thanks to Kent Pitman for responding to Tim Bradshaw, otherwise I
> wouldn't have seen the latter's post as it did not show up on the
> server I use for reading.  Usenet works in strange ways sometimes;
> I so much wish I had access to the `true definitive' NNTP server for
> comp.lang.lisp (note that Deja does not qualify as a _NNTP_ server).)

Usenet being what it is, there is no definitive NNTP server.  But
IIRC, Deja has recently started providing NNTP access, if I understood 
the line "read ... with your favorite newsreader" correctly).  OTOH I
find Deja to be quite a bit behind other NNTP servers.  I only use it, 
when behind company firewalls, and then I hate their user interface
(but then again I hate most WWW UIs).

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Vassil Nikolov
Subject: Re: eof-error-p/eof-value
Date: 
Message-ID: <l03130300b3caf796aad9@195.138.129.108>
Pierre R. Mai wrote:                [1999-08-02 01:32 +0200]

  > Vassil Nikolov <········@poboxes.com> writes:
  [...]
  > > I so much wish I had access to the `true definitive' NNTP server for
  > > comp.lang.lisp (note that Deja does not qualify as a _NNTP_ server).)
  > 
  > Usenet being what it is, there is no definitive NNTP server.

Yes, of course, that was just an expression of slight frustration.

  > But
  > IIRC, Deja has recently started providing NNTP access, if I understood 
  > the line "read ... with your favorite newsreader" correctly).

I saw that, but I also read that they charge for it (ca. $10/month or
ca. $70/year), so it becomes a matter of subscribing to (yet) another
ISP, sort of.  There might be better deals.

  >  OTOH I
  > find Deja to be quite a bit behind other NNTP servers.  I only use it, 
  > when behind company firewalls, and then I hate their user interface
  > (but then again I hate most WWW UIs).

For me the main problem with their WWW interface is that it does not
keep track of read messages, so I can only mark the whole group
unread at once, which does not work for me.  But their mail-to-news
gateway works fine (or at least has been working fine for me for the
past month or so); now their news-to-mail gateway sends messages
with delays (don't know if this is intentional) and also seems to miss
posts.


Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.





 Sent via Deja.com http://www.deja.com/
 Share what you know. Learn what you don't.
From: Kent M Pitman
Subject: Re: eof-error-p/eof-value
Date: 
Message-ID: <sfwg124x9d1.fsf@world.std.com>
Tim Bradshaw <···@tfeb.org> writes:

> I think that kind of works but it's appallingly difficult to use.  If
> I understand you, your are using the supplied-p feature to
> distinguish between:
> 
> 	(foo blarble)	; signal error on EOD
> 
> 	(foo blarble nil) ; return NIL on EOD
> 	
> 	(foo blarble 'EOD) ; return EOD on OED
> 

Ah, I read his message earlier and was struggling to understand the
relevance of the arg being last, but now I do.  Thanks for deciphering this.

> I think that would *work*, but it's a terrible design, because in lots
> of cases you now have to have a little switch in the caller:
> 
> 	(if want-error-p
> 	   (foo blarble)
> 	   (foo blarble nil))
> 
> rather than:
> 
> 	   (foo blarble want-error-p)

Yes.  I use this supplied-p thing from time to time, but I almost
always regret it.  It definitely composes badly.

Further, there's a constant pressure to add args, and optionals
get less friendly as you add more of them.  I recommend starting out
with keywords, so you don't end up with a problem if you have to skip
over an optional.  Wanting to supply a later arg but having no way 
to talk about the middle arg being missing is a problem.

> Also I have no idea if supplied-p parameters are supported in other
> Lisps, though that may not be a big issue.

Well, in scheme for example:
 (define (foo arg1 . maybe-arg2)
    (if (cdr maybe-arg2) ;supplied-p
        ... (car maybe-arg2) ... ;i.e., definitely-arg2
	))
It can often be glossed, in other words,.  But it's ugly.  Also, one
can always write:

 (define (foo arg1 arg2 use-arg2-p) ...)

though that bears a striking resemblance to the argument convention
READ and friend presently use with the 
 &optional eof-error-p eof-value




 
From: Rob Warnock
Subject: Re: eof-error-p/eof-value
Date: 
Message-ID: <7o3q57$t1i3@fido.engr.sgi.com>
In article <···············@world.std.com>,
Kent M Pitman  <······@world.std.com> wrote:
+---------------
| Tim Bradshaw <···@tfeb.org> writes:
| > Also I have no idea if supplied-p parameters are supported in other
| > Lisps, though that may not be a big issue.
| 
| Well, in scheme for example:
|  (define (foo arg1 . maybe-arg2)
|     (if (cdr maybe-arg2) ;supplied-p
|         ... (car maybe-arg2) ... ;i.e., definitely-arg2
| 	))
+---------------

I think you probably meant something like this:

   (define (foo arg1 . maybe-arg2)
      (if (not (null? maybe-arg2)) ;supplied-p
          ... (car maybe-arg2) ... ;i.e., definitely-arg2
  	))

+---------------
| It can often be glossed, in other words,.  But it's ugly.
+---------------

Indeed. I often find myself writing destructuring macros to help out.

By the way, some Schemes have a construct called "case-lambda":

	<URL:http://www.cs.rice.edu/CS/PLT/packages/doc/mzscheme/node22.htm>
	The case-lambda form creates a procedure that dispatches to a
	particular body of expressions based on the number of arguments
	it receives. This provides a mechanism for creating variable-arity
	procedures with more control and efficiency than using a ``rest arg''.

So using case-lambda, the above example [extended slightly] becomes:

	(define foo
	  (case-lambda
	    ((arg1) ...what to do if only one arg given...)
	    ((arg1 arg2) ...what to do if exactly two args...)
	    ((arg1 arg2 arg3 . the-remainder) ...three or more...)))


-Rob

-----
Rob Warnock, 8L-855		····@sgi.com
Applied Networking		http://reality.sgi.com/rpw3/
Silicon Graphics, Inc.		Phone: 650-933-1673
1600 Amphitheatre Pkwy.		FAX: 650-933-0511
Mountain View, CA  94043	PP-ASEL-IA
From: Kent M Pitman
Subject: Re: eof-error-p/eof-value
Date: 
Message-ID: <sfwvhaxwm5v.fsf@world.std.com>
····@rigden.engr.sgi.com (Rob Warnock) writes:

> I think you probably meant something like this: [corrected scheme code]

Yeah. I do regularly program in Scheme as of this year, since I work with
Jonathan Rees and he writes his code in that.  (We use his Scheme emulator
in CL and each of us go back and forth between Lisp and Scheme.)  But I'm
still not super-practiced at Scheme in its day-to-day details.  Thanks for
the correction, and for the note about case-lambda.