"The assertion-violation procedure should be called when an invalid
call to a procedure was made, either passing an invalid number of
arguments, or passing an argument that it is not specified to handle."
I take it that "assert" is left for everything else; in particular to
help the procedure implemeter verify that the procedure, his
implementation of it, is behaving as expected?
assert is a macro in R6RS, basically:
(define-syntax assert
(syntax-rules ()
[(_ expr)
(unless expr
(assertion-violation #f "assertion failed"))]))
Cheers
leppie
When are you likely to use it?
Actually, R6RS says it must return the value of expr if it's not #F:
(define-syntax assert
(syntax-rules ()
((_ expr)
(let ((x expr))
(if x x (assertion-violation #F ---))))))
Ikarus and Larceny do not, Ypsilon does, didn't check others.
R6RS does not say what assert should do if expr returns a number of
values other than 1, but maybe what it should do is implied by another
part of the report?
--
: Derick
----------------------------------------------------------------
assertion-violation is a convenient way to add &who, &message, and
&irritants conditions to the exception. It should be used for failed
checks of arguments or other user mistakes to give consistent and
portable exceptions.
I believe assert was intended to be useful for checking internal
invariants / assumptions, similar to how C's assert is used, and this
is why "Implementations should exploit the fact that assert is syntax
to provide as much information as possible about the location of the
assertion failure." but this information is implementation-dependent.
I think using assert to check your assumptions is good, and I use it
when I'm not certain my assumptions are correct or to indicate non-
obvious assumptions. I don't understand why it's in the report the
way it is. I would think it should always return unspecified values
and should be specified that it may not be evaluated (e.g., turned off
via a compiler / interpreter option, similar to C's #define NDEBUG).
--
: Derick
----------------------------------------------------------------
> should be specified that it may not be evaluated (e.g., turned off via a
> compiler / interpreter option, similar to C's #define NDEBUG).
Do any r6rs compilers provide that feature? (an assertions-off
compilation mode) I'd appreciate it. I suppose that one could do it
oneself by arranging to redefine assert as values for the compilation.
Cheers,
--
Andrew
No, but it is easily enough defined. An example can be seen in the
psyntax sources in the (psyntax config) library.
Also, you cant redefine assert, unless you import another definition
from another library, in all the libraries used.
Cheers
leppie
> I would think it should always return unspecified values
I agree with that.
Cheers
leppie
> I take it that "assert" is left for everything else; in particular to
> help the procedure implemeter verify that the procedure, his
> implementation of it, is behaving as expected?
Note the note:
>> Implementations should exploit the fact that `assert' is syntax to
>> provide as much information as possible about the location of the
>> assertion failure.
In particular, it may be difficult for `assertion-violation' to provide
the same level of detail about the failure as it's a procedure, and the
call to it may be a tail call. (In fact, it often is.)
--
Cheers =8-} Mike
Friede, Völkerverständigung und überhaupt blabla
assertion-violation will provide more consistent, portable messages;
but assert will be in a better position to easily expose more details.
That sounds like tension!
Which one of these would be the best thing for reporting erroneous
utilization of macros? I mean something like "This macro expects at
least 2 operands that are the day and week..." or something.
I would say a third one: syntax-violation
Right, duh, thanks Michele; I even had that one in my notes! :)
What about syntax-violation ?
--
Bogdan
R6RS says that :
1. assert emits &assertion condition
and
2.
"...
(define-condition-type &assertion &violation
make-assertion-violation assertion-violation?)
This type describes an invalid call to a procedure, either passing an
invalid number of arguments, or passing an argument of the wrong
type.
..."
1&2 It mean that 'assert is about procedure call safety or in other
words about procedure pre-condition check.
If you want to turn-off this safety for all procedures than I have
following questions regarding mode with assert turned-off:
1. What about procedures accepting input from users ? Should they
behave unsafe ?
2. What about standard procedures ? Do you want to turn-off safety
for them as well ? Or they should use different assertion mechanism ?
3. If assert is associated with debug configuration then which
mechanism should be used to implement checks for release
configuration ?
--
Bogdan
If that's all &assertion is for, why doesn't the specification of
assert say that's all assert should be used for? and why are they
named "assertion" and "assert" if they're not to be used for all types
of assertions? I think exceptions with &assertion make sense for
argument checking because you're asserting what must be true, but if
R6RS's intent was to have a condition type and other facilities only
for argument checking then the name should not be "assertion" and that
intent should have clearly and consistently been made.
> If you want to turn-off this safety for all procedures than I have
> following questions regarding mode with assert turned-off:
> 1. What about procedures accepting input from users ? Should they
> behave unsafe ?
> 2. What about standard procedures ? Do you want to turn-off safety
> for them as well ? Or they should use different assertion mechanism ?
> 3. If assert is associated with debug configuration then which
> mechanism should be used to implement checks for release
> configuration ?
I'm not suggesting turning off debug mode should turn off argument
checks or other checks required to make high-level safe languages and
libraries. I want consistent portable exceptions for required
checks. I think exceptions should be able to be used portably
programmatically and not just for the base exception handler to print
messages for humans. An assert with implementation-specific semantics
for what the exceptions it raises are, used for required checks, is
not robust for portable programmatic purposes, IMO. Why is an
implementation-specific assert in a standard that is supposed to be
about portability?
Also, I question whether assert, with any semantics, should even be in
the standard. With compatibility libraries, implementations can
provide their things that tell file name, line number, etc. and
library / framework writers can make a consistent portable assert that
uses them to achieve whatever qualities users might want and we can
have different competing asserts for different uses and users.
--
: Derick
----------------------------------------------------------------
When and why would a call to assertion-violation or assert be a tail
call? Please point us to somewhere we can see that this has been done
often or give us an example that shows why it would be done often.
Thanks,
--
: Derick
----------------------------------------------------------------
> When and why would a call to assertion-violation or assert be a tail
> call? Please point us to somewhere we can see that this has been done
> often or give us an example that shows why it would be done often.
This is a fairly common pattern:
(define (proc arg)
(if (ok? arg)
(compute arg)
(assertion-violation 'proc "arg not ok" arg")))
Right, but assertion-violation never returns so I don't find this case
justifying. I mentioned "assertion-violation or assert" because you
mentioned only assertion-violation and I wasn't sure what you meant.
What's an example, of a case that would occur often, of assert being
in tail position where its return value would actually be used?
Thanks,
--
: Derick
----------------------------------------------------------------
Also, what's a realistic example in which the return value of assert
would be used in any type of case (not necessarily the tail position
case)?
--
: Derick
----------------------------------------------------------------
It is still called, and by the time it escapes somewhere else, the
previous stack frame is gone!
If it doesn't, the Scheme is not doing proper tail recursion :)
Cheers
leppie
> Also, what's a realistic example in which the return value of assert
> would be used in any type of case (not necessarily the tail position
> case)?
(define (lookup ht key)
(hashtable-ref (assert (and (hashtable? ht) ht)) key #f))
OK, maybe not realistic, but rather why I feel it should not return a
specified value(s).
I would even argue that the assert macro should be a dummy definition,
allowing it to be used before other definitions, else you end up with:
(define (foo bar)
(assert (bar? bar))
(let ()
(define baz 10)
...))
Cheers
leppie
This is good programming style, even more I'd like to have contract
library which allows me to do:
(define/c (foo (bar : bar?) ) : foo-result?
...)
This style allows me to have some documenting tool which can capture
procedures signature.
But! There are exceptions to your suggestion. As stated in R6RS
"5.4. Argument checking" there are situations when full check of
arguments can be expensive. And in this case you will need assert or
something like this to check *part* of argument only on when this
part is really involved in evaluation.
--
Bogdan
It can be logically concluded from the fact that it raises &assertion
condition which in turn describes invalid arguments.
> and why are they
> named "assertion" and "assert" if they're not to be used for all types
> of assertions?
It is not question to me, this is what r6rs says.
But in many situations particular programming language terms have more
semantics than equivalent English terms or general CS terms. And in
this case both assert and &assertion mean only procedure argument
checks.
> I think exceptions with &assertion make sense for
> argument checking because you're asserting what must be true, but if
> R6RS's intent was to have a condition type and other facilities only
> for argument checking then the name should not be "assertion" and that
> intent should have clearly and consistently been made.
Completely agree with you. invalid-argument, missing-argument ... etc.
names should be much more readable then assert/assertion.
Also those identifiers can be improved if using contracts terminology
which splits all asserts (not only argument checking) into 4
categories:
1. pre-condition / require
2. post-conditions / ensure
3. invariant checks
4. debug assertions (turned off in release).
In most cases debug assertions should terminate program
execution providing as much information to developer as possible
and alternative to terminating program can suggest to activate
debugger-tool.
>
> I'm not suggesting turning off debug mode should turn off argument
> checks or other checks required to make high-level safe languages and
> libraries. I want consistent portable exceptions for required
> checks. I think exceptions should be able to be used portably
> programmatically and not just for the base exception handler to print
> messages for humans.
> An assert with implementation-specific semantics
> for what the exceptions it raises are, used for required checks, is
> not robust for portable programmatic purposes, IMO. Why is an
> implementation-specific assert in a standard that is supposed to be
> about portability?
The only implementation-dependent part of assert is message in
message-condition, right? In this case I see no problem with
portability, do you?
> Also, I question whether assert, with any semantics, should even be in
> the standard.
I think assert form is accidentally :) borrowed from c/c++ where it
has semantics of mentioned debug assertion and again accidentally it
was puzzled with pre-conditions idea.
> With compatibility libraries, implementations can
> provide their things that tell file name, line number, etc.
100% agree. It is the most annoying thing about assert.
> and
> library / framework writers can make a consistent portable assert that
> uses them to achieve whatever qualities users might want and we can
> have different competing asserts for different uses and users.
--
Bogdan
It's not exactly what you've asked for, but you should definitely look
at the PLT Scheme contract library:
http://docs.plt-scheme.org/guide/contracts.html
sam th
> It's not exactly what you've asked for, but you should definitely look
> at the PLT Scheme contract library:
> http://docs.plt-scheme.org/guide/contracts.html
>
> sam th
While we are pimping libraries :)
https://ironscheme.svn.codeplex.com/svn/IronScheme/IronSchemeConsole/ironscheme/contracts.ss
https://ironscheme.svn.codeplex.com/svn/IronScheme/IronSchemeConsole/ironscheme/contracts-helper.ss
The only part that is non-R6RS is string-split as I like to make my
parameters like: foo:bar where foo is the name, bar is the 'type' that
supplies the bar? predicate. So bar is the predicate less the ? (I
know its a bit limiting due to enforcing the '?' but it looks a lot
better than foo:bar? :)
Cheers
leppie
Guess where did I get this idea :)
Seriously, I wrote my own R6RS contract library somewhat similar to
PLT. Difference is that my library can emit detailed human-readable
messages describing failure. Even for very complicated constraints.
What is wrong with my library is performance. Despite very clean and
simple procedure based implementation, it is about 200-300 times
slower (for PLT compiled executable) than dumb assert expression. I
already have macros&monads based implementation which is only 10-20
slower than assert equivalent. But I have reasons to think that
performance for most cases can be close to the assert equivalent.
I would appreciate if you can suggest any sources/articles describing
contracts/constraints implementations in scheme. Including PLT one
which I was not able to grok from sources because of complexity.
--
Bogdan
Looks like we all are spinning around the same ideas :)
Since contract library is needed anyway for r6rs wouldn't it
be better to join our efforts ?
> The only part that is non-R6RS is string-split as I like to make my
> parameters like: foo:bar where foo is the name, bar is the 'type' that
I do not feel that joining argument identifier and argument type
predicate is a good idea. It couldn't solve contracts problem
since argument contracts can be (and in many cases are) much more
complicated than dumb predicate check. Please correct me if i did
understand your implementation incorrectly.
For details please look at various PLT contract combinators (like or/
c) and their role for PLT documentation. Besides there are exceptions/
conditions which are part of contract as well (I saw nothing in PLT on
this).
How miuch would a R6RS port of it cost? :)
I'm not sure what you mean here. The PLT contract system provides
human-readable error messages, like this:
'n broke the contract (-> number? number?) on x; expected <number?>,
given: #f
(program at the end of this message)
>
> What is wrong with my library is performance. Despite very clean and
> simple procedure based implementation, it is about 200-300 times
> slower (for PLT compiled executable) than dumb assert expression. I
> already have macros&monads based implementation which is only 10-20
> slower than assert equivalent. But I have reasons to think that
> performance for most cases can be close to the assert equivalent.
>
> I would appreciate if you can suggest any sources/articles describing
> contracts/constraints implementations in scheme. Including PLT one
> which I was not able to grok from sources because of complexity.
There are a number of papers on the PLT Contract system. You should
look here:
http://www.ece.northwestern.edu/~robby/pubs/
and click on 'Contracts' on the left-hand side to narrow it down to
just the contract papers.
sam th
Program:
(module m scheme
(define (x a) 1)
(provide/contract [x (number? . -> . number?)]))
(module n scheme
(require 'm)
(x #f))
(require 'n)
(number? . -> . number?) shows off PLT's "infix notation" syntax.
(a . b . c) becomes (b a c)
> Looks like we all are spinning around the same ideas :)
> Since contract library is needed anyway for r6rs wouldn't it
> be better to join our efforts ?
>
I believe Derrick Eddington also made a full-featured contract
library. In my case, I just need something simple to check incoming
arguments. Do you have a URL to your library perhaps?
> > The only part that is non-R6RS is string-split as I like to make my
> > parameters like: foo:bar where foo is the name, bar is the 'type' that
>
> I do not feel that joining argument identifier and argument type
> predicate is a good idea. It couldn't solve contracts problem
> since argument contracts can be (and in many cases are) much more
> complicated than dumb predicate check. Please correct me if i did
> understand your implementation incorrectly.
That is true, but my need for the library was purely convenience for
library writer point of view, asserting argument types gets a bit
tedious.
If the check is more complex than a predicate, or something that can
be defined as one, eg number-smaller-than-10-and-larger-than-5?, then
I would simply just check it 'normally' at the start of the procedure.
Like said, the motivation was convenience rather than a strict
contract definition (I dont really care for checking return values, as
I am returning it).
Cheers
leppie
That depends on how you interpret "If <expression> returns #f, an
exception with condition types &assertion and &message is raised.".
Does that mean it can only contain those conditions?
$ cat assert.sps
(import (rnrs (6)))
(assert (not 'foo))
$ ikarus --r6rs-script assert.sps
Unhandled exception:
Condition components:
1. &assertion
2. &who: assert
3. &message: "assertion failed"
4. &irritants: ((not 'foo))
5. &source-position:
file-name: "assert.sps"
character: 21
$ larceny -r6rs -program assert.sps
Error: no handler for exception #<record &compound-condition>
Compound condition has these components:
#<record &assertion>
#<record &message>
message : "assertion failed"
#<record &irritants>
irritants : ((not 'foo))
Terminating program execution.
$ ypsilon --dump-condition assert.sps
error: assertion failed in expression (not 'foo)
#<condition
&assertion (&violation &serious)
&message: assertion failed in expression (not 'foo)
&irritants: ()
>
backtrace:
0 (assertion-violation #f "assertion failed in expression (not
'foo)")
$
> In this case I see no problem with portability, do you?
I think I do. In order for exceptions' information to be useful
programmatically and portably, it needs to be represented in a
portable (consistent) way. Even if assert's message strings were
portable, having to parse information out of them would be stupid,
especially since general purpose portable condition types are
available.
If assert is only used for debug mode then portable programmatic
usefulness probably isn't needed. But if assert is used for argument
checking then I think it is needed.
I test that my procedures' exceptions are portable. I test their main
condition (&assertion, &error, &warning, &i/o, etc.) and the fields'
values of their &who, &message, &irritants or whatever. Being able to
test code on multiple systems is one reason for argument check
exceptions to be useful portably.
Just like how exceptions are used in precise portable ways for
programs to decide how to handle exceptional situations other than bad
arguments, programs should be able to decide how to handle bad
argument exceptions and for this they need information. This could be
useful for a program that supervises other programs and wants to know
precisely who failed and for what reason, rather than just "some
argument check failed", so it can decide what to do based on that
information. I see this as following the spirit of making things
useful for all the future uses and complexity growth we can't
foresee. I don't think the language standard should attempt to figure
this out, but I think it should have portable consistent exceptions
for its things.
> > With compatibility libraries, implementations can
> > provide their things that tell file name, line number, etc.
>
> 100% agree. It is the most annoying thing about assert.
What do you mean?
--
: Derick
----------------------------------------------------------------
I didn't. I just have an argument checking macro:
> (import (xitomatl define))
> (define/? (p a (b string?) c
(d (lambda (x) (and (integer? x) (exact? x))))
(e (if (null? a) vector? list?))
. #(args (lambda (x) (andmap pair? args))))
(list a b c d e args))
> (p 1 "two" 3 4 5 '(6 . 7))
Unhandled exception
Condition components:
1. &assertion
2. &who: p
3. &message: "argument check failed"
4. &irritants: (5)
5. &argument-name: e
6. &predicate: (if (null? a) vector? list?)
>
(I think I should rename &predicate to &predicate-expression.)
And some macros like:
> (define/who (foo) who)
> (foo)
foo
> (define/AV (bar) (AV "oops"))
> (bar)
Unhandled exception
Condition components:
1. &assertion
2. &who: bar
3. &message: "oops"
4. &irritants: ()
>
> (I dont really care for checking return values, as I am returning it).
Me neither.
--
: Derick
----------------------------------------------------------------
> On Feb 16, 11:20 pm, Michael Sperber <sper...@deinprogramm.de> wrote:
>> Derick Eddington <derick.edding...@gmail.com> writes:
>> > When and why would a call to assertion-violation or assert be a tail
>> > call? Please point us to somewhere we can see that this has been done
>> > often or give us an example that shows why it would be done often.
>>
>> This is a fairly common pattern:
>>
>> (define (proc arg)
>> (if (ok? arg)
>> (compute arg)
>> (assertion-violation 'proc "arg not ok" arg")))
>
> Right, but assertion-violation never returns so I don't find this case
> justifying. I mentioned "assertion-violation or assert" because you
> mentioned only assertion-violation and I wasn't sure what you meant.
There's probably a misunderstanding at work: In common implementations
of tail recursion, if the assertion violation in the above example
happens, the frame for the call to `proc' will have disappeared: It is
therefore up to the message with `assertion-violation' to tell you where
the violation happened; the "stack trace" won't tell you.
I forgot you'd also asked about `assert' - sorry about that.
> What's an example, of a case that would occur often, of assert being
> in tail position where its return value would actually be used?
I don't know - it does seem hard to imagine such a scenario.
I thought you were mentioning tail calls as a reason for assert
returning a value. Sorry for assuming too much about what you said.
So, the stack frame being reused if assertion-violation is tail-called
is why we need R6RS's assert. But error and other exception raisers
have the same tail call issue but they have no analogous alternative.
If I were to use assert for argument checking, it wouldn't be in tail
position because I'd do the check in the assert before the other
expressions. It seems to me this all is really an argument for not
using exception raisers in tail position so we can have better stack
traces.
I know assert is a minor issue so I'll drop it now. I've just been
getting more and more frustrated trying to understand R6RS.
--
: Derick
----------------------------------------------------------------
>
> So, the stack frame being reused if assertion-violation is tail-called
> is why we need R6RS's assert. But error and other exception raisers
> have the same tail call issue but they have no analogous alternative.
> If I were to use assert for argument checking, it wouldn't be in tail
> position because I'd do the check in the assert before the other
> expressions. It seems to me this all is really an argument for not
> using exception raisers in tail position so we can have better stack
> traces.
By just using assert (with the default implementation message) will
not generally give you sufficient information where the error occured
(with the exclusion of psyntax providing a source location :) ).
By using assertion-violation, you generally supply a helpful message
and who.
It would have been nice if assert (and assertion-violation with a #f
who) could have had some implementation defined lookup, similar to
what syntax-violation does, but from the R6RS and the PLT tests, it
seems this is against the law!
Cheers
leppie
I think no and IMO assert is not enough standardized.
<snip>
> > > With compatibility libraries, implementations can
> > > provide their things that tell file name, line number, etc.
>
> > 100% agree. It is the most annoying thing about assert.
>
> What do you mean?
That lack of standard on source position information in assert and
other places like syntax-violation causes lot of problems in portable
r6rs programming and especially for portable development tools.
--
Bogdan
Not yet. Next month I'll be busy but after that i'll write some minor
docs and will put everything on launchpad.
Meanwhile short description:
Core is constraints library which is basically a tool for building
predicates to check values and emit human readable information in
case of failure. On top of this library there are two others:
contracts
and unit-testing (integration into Vim/Gvim provided).
GVim integration includes possibility to run particular test, test-
fixture or test-suite using your mouse only (like in TestDriven.Net)
and see list of errors in vim's quickfix window.
At the end you can find constraints tests snippets.
> Like said, the motivation was convenience rather than a strict
> contract definition (I dont really care for checking return values, as
> I am returning it).
I understand this, *but* by specifying contract for returned value you
also document your code (idea from PLT). Having nice macros for
contracts you can generate reasonable documentation having simple doc
tool. You will rarely need this functionality in project which
contains single
developer ... but in case of team specifying return value can avoid a
lot of problems.
Now extend contracts idea on exceptions too. Are you sure that you can
easily remember and control all exceptions raised by your procedure ?
--
Bogdan
Constraints tests snippet:
<code>
(expect-diagnosis
(verify 'foo (or/c number? string?))
'(got (symbol foo)
(expected: number?)
(expected: string?)))
(expect-diagnosis
(verify '(a . b) (pair/c symbol? string?))
'(got (pair (a . b))
(for cdr
(got (symbol b)
(expected: string?)))))
(expect-diagnosis
(verify '(a "b" "444") (list/c symbol? string? number?))
'(got (list (a "b" "444"))
(for (item-at-index 2)
(got (string "444")
(expected: number?)))))
(expect-diagnosis
(verify "126"
(for/c string-length
(and/c (>=/c 5) (<=/c 10))))
'(got (string "126")
(for string-length
(got (number 3)
(expected: (>= 5))))))
(expect-success
(verify (partition even? '(3 1 4 1 5 9 2 6))
(values/c list? list?)))
</code>
Making an independent portable assert is doable with compatibility
libraries and if systems provide equivalent functionality (or at least
functionality which can be made to be equivalent):
(library (acme assert)
(export
assert
debug-mode
expression-condition?
condition-expression
source-location-condition?
condition-source-location-file-name
condition-source-location-character-position
condition-source-location-procedure-name)
(import
(except (rnrs) assert)
(acme assert compat)) ;; Assumes implicit phasing :-)
(define-condition-type &expression &condition
make-expression-condition expression-condition?
(expression condition-expression))
(define-condition-type &source-location &condition
make-source-location-condition source-location-condition?
(file-name condition-source-location-file-name)
(character-position condition-source-location-character-position)
(procedure-name condition-source-location-procedure-name))
(define (assert-failed expr file-name char-pos proc-name)
(raise (condition
(make-assertion-violation)
(make-message-condition "debugging assertion failed")
(make-expression-condition expr)
(make-source-location-condition file-name char-pos proc-
name))))
(define-syntax assert
(lambda (stx)
(if (debug-mode)
(syntax-case stx ()
((_ expr)
(let ((file-name (source-file-name stx))
(char-pos (source-character-position stx))
(proc-name (source-containing-procedure-name stx)))
#`(if expr
(values)
(assert-failed 'expr #,file-name #,char-pos '#,proc-
name)))))
;; Compilers should know when this is a superfluous
;; expression and eliminate it.
#'(values))))
)
(library (acme assert compat)
(export
debug-mode
source-file-name
source-character-position
source-containing-procedure-name)
(import
(only (ultra-scheme debugging)
debug-mode)
(only (ultra-scheme syntax-utilities)
source-file-name
source-character-position
source-containing-procedure-name))
;; Or maybe build on Ultra Scheme's functionality to make what we
need...
)
(library (acme assert compat)
(export
debug-mode
source-file-name
source-character-position
source-containing-procedure-name)
(import
(rnrs)
(srfi :39 parameters))
(define debug-mode (make-parameter #T))
(define (source-file-name stx)
"foo/bar.sls")
(define (source-character-position stx)
12345)
(define (source-containing-procedure-name stx)
#'do-something)
)
Under Ikarus:
> (import (acme assert))
> (assert (not 'true))
Unhandled exception
Condition components:
1. &assertion
2. &message: "debugging assertion failed"
3. &expression: (not 'true)
4. &source-location:
file-name: "foo/bar.sls"
character-position: 12345
procedure-name: do-something
> (parameterize ((debug-mode #F))
(eval '(begin (assert (not 'true))
'done)
(environment '(except (rnrs base) assert)
'(acme assert))))
done
> (debug-mode #F)
> (assert (not 'true))
>
--
: Derick
----------------------------------------------------------------
> So, the stack frame being reused if assertion-violation is tail-called
> is why we need R6RS's assert. But error and other exception raisers
> have the same tail call issue but they have no analogous alternative.
> If I were to use assert for argument checking, it wouldn't be in tail
> position because I'd do the check in the assert before the other
> expressions.
You're right: I doubt there's a strong rationale for `assert' returning
the value of its operand. As you can imagine, `assertion-violation',
`error' and `syntax-violation' were there first (reflecting the most
important entry points into the condition hierarchy), and `assert' was
added, I believe, to duplicate similar-looking functionality in, say,
Java or C.
Only my 5c:
1. IMHO it should be position
instead of character-position since byte counting is more
natural than character counting which assumes particular
encoding.
2. Alternatively to counting position or line/column it is possible
to use syntax object as source position information.
AFAIK all existing implementations allow to obtain source position
information from syntax-object. If standard forced this fact then
there will be no need in separate expression condition and source
position condition. Also it can help in
standardization of syntax-violations.
3. R6RS defines &assertion for argument check only.
Your assert is mentioned debug-assert which is *completely*
different from argument checking. It means that you should
use your own condition or *fix* meaning of standard &assertion.
--
Bogdan
On Feb 19, 2:43 am, Derick Eddington <derick.edding...@gmail.com>
wrote:
Maybe another time. Feel free to do whatever you want with that draft
(acme assert).
> Only my 5c:
> 1. IMHO it should be position
> instead of character-position since byte counting is more
> natural than character counting which assumes particular
> encoding.
I think the opposite. Textual source-code is in terms of characters.
I don't care what byte it was at -- that assumes a particular
encoding.
> 2. Alternatively to counting position or line/column it is possible
> to use syntax object as source position information.
> AFAIK all existing implementations allow to obtain source position
> information from syntax-object. If standard forced this fact then
> there will be no need in separate expression condition and source
> position condition. Also it can help in
> standardization of syntax-violations.
Well, I'm becoming more and more convinced that if it can be done
independently via compatibility libraries there's no reason to weigh
down the language standard (and the people who spend time on it) and
force implementors with legislated assumptions that might not be what
everyone wants. After all, Scheme source-code is actually a data
structure we only view as a textual representation, and so it's
possible (and one of the more unique useful awesome things about
Scheme) source-code which was not "read in" very well may be evaluated
and it would have no textual source location. With compatibility
libraries, if an implementation doesn't provide whatever necessary
support, it won't have a compatibility library and so attempting to
use it will fail to find the library, which will let you know what is
needed so you can lobby that implementation to add support.
> 3. R6RS defines &assertion for argument check only.
> Your assert is mentioned debug-assert which is *completely*
> different from argument checking. It means that you should
> use your own condition or *fix* meaning of standard &assertion.
I say the meaning of &assertion should match its very general name.
Since conditions are compound and the types extensible, it's really
the entire "shape and color" that determines the full meaning, and I
think this is a main quality that makes them so flexibly useful. A
sub-type of &assertion could be made for failed argument checks, or a
separate type; I don't know what would be better.
--
: Derick
----------------------------------------------------------------
I still feel the line and column combo is the best indicator of
errors, preferably with an 'end' column and 'end' line too.
This way a text editor needs not to know anything about the language.
Cheers
leppie
+1. Besides line numbering is less sensitive to encoding.
--
Bogdan
> Exactly! Since original assert is nearly unusable.
Unusable? I use it all the time, and it works pretty well for me.
It would be more usable if you could include an optional message, who
and irritants. Currently the R6RS does not even allow the who part to
be 'auto-detected' when given an #f argument.
It works well for simple cases though.
Cheers
leppie
2. Procedure argument checking via assert semantics is nearly unusable
since it
- doesn't provide information about irritants (impossible to eval
them)
- provides no standardized information to highlight source position
of failure i.e. it is impossible to write portable development
tool (IDE, editor ...) capturing this information.
- provides no possibility to supply custom message which explains
details of argument rejection.
Also you can not use assertion-violation directly to have better
argument checking just because it does not provide source locations
information which is *must* for development.
Note that procedure argument checking coding style should be const
from the beginning of your project. Normally developer should not
spend week to fix all argument checking just because r7rs has some
"better idea" ...
That is why i prefer to write my own debug-assert, contract checking
asserts and not to use assert/assert-violation directly.
--
Bogdan
On Feb 23, 9:17 am, Michael Sperber <sper...@deinprogramm.de> wrote: