Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for SRFI 227 #788

Merged
merged 1 commit into from
Nov 24, 2021
Merged

Add support for SRFI 227 #788

merged 1 commit into from
Nov 24, 2021

Conversation

dpk
Copy link
Contributor

@dpk dpk commented Nov 24, 2021

No description provided.

@ashinn ashinn merged commit 2820aab into ashinn:master Nov 24, 2021
@ashinn
Copy link
Owner

ashinn commented Nov 24, 2021

Thanks!

@mnieper
Copy link
Collaborator

mnieper commented Nov 24, 2021 via email

@dpk
Copy link
Contributor Author

dpk commented Nov 24, 2021

Oh, interesting. Serves me right for assuming your let-optionals[*] was the same as Chibi’s. The precise difference is that SRFI 227’s let-optionals[*] also handles non-optional arguments, as far as I can see?

Edit: Okay, yes, that’s correct, and also (chibi optional)’s opt-lambda doesn’t handle rest arguments, it seems (although it also looks like it’s actually meant to?)

@mnieper
Copy link
Collaborator

mnieper commented Nov 24, 2021 via email

@dpk
Copy link
Contributor Author

dpk commented Nov 24, 2021

@ashinn, what would be your preferred approach here? Should I extend (chibi optional) to support the extended argument list forms from SRFI 227, or should (srfi 227) use its own implementation?

@mnieper
Copy link
Collaborator

mnieper commented Nov 24, 2021 via email

@ashinn
Copy link
Owner

ashinn commented Nov 24, 2021

Chibi has no restriction on mutating the first argument.

@mnieper
Copy link
Collaborator

mnieper commented Nov 24, 2021

Chibi has no restriction on mutating the first argument.

I was referring to this comment: https://github.com/ashinn/chibi-scheme/blob/master/lib/chibi/optional.scm#L31.

@ashinn
Copy link
Owner

ashinn commented Nov 24, 2021

(chibi optional) includes that restriction for future-proofing, however currently the implementation will "work" just as expected if you choose to include a test case that mutates the first argument.

There's nothing wrong with the (chibi optional) spec being more strict than the (srfi 227) spec if the same implementation satisfies both.

@mnieper
Copy link
Collaborator

mnieper commented Nov 24, 2021

(chibi optional) includes that restriction for future-proofing, however currently the implementation will "work" just as expected if you choose to include a test case that mutates the first argument.

I know that you have added a "fix" to optionals.sld when it is used outside of Chibi, but the fix is not in init-7.scm, which contains the definition of let-optionals* for Chibi if I am not mistaken. Of course, it would be trivial to amend the latter as well.

There's nothing wrong with the (chibi optional) spec being more strict than the (srfi 227) spec if the same implementation satisfies both.

Sure. Anyway, the discrepancy between Chibi's implementation (of its own spec) and SRFI 227 that actually matters is that SRFI 227 allows bindings without defaults in let-optionals.

The expression

(let-optionals '(1 2)
    (x . y)
  (list x y))

is valid in SRFI 227 and evaluates to (1 (2)).

@mnieper
Copy link
Collaborator

mnieper commented Nov 24, 2021

PS Another difference between what Chibi implements and what SRFI 227 demands is that the rest argument in let-optionals(*) in SRFI 227 becomes a newly allocated list. In Chibi's implementation, it shares the tail with the list that is being deconstructed. (This is also connected to the question of what happens if the default expressions mutate the actual list structure being deconstructed (and not just set!s the argument). SRFI 227 says that this happens after the deconstruction of the list.)

@ashinn
Copy link
Owner

ashinn commented Nov 24, 2021

I know that you have added a "fix" to optionals.sld when it is used outside of Chibi, but the fix is not in init-7.scm, which contains the definition of let-optionals* for Chibi if I am not mistaken. Of course, it would be trivial to amend the latter as well.

The fix is not needed in init-7.scm because that is only used by Chibi and the order of evaluation is guaranteed in Chibi.
Again - if you think there is an error please provide a failing test case before claiming there is an error.

I've pushed support for non-optional optional arguments in let-optionals.

I'll have to think about newly allocating a list for rest arguments. That seems like a mistake in the spec, making opt-lambda inconsistent with lambda for which it is an error to mutate the rest argument.

@mnieper
Copy link
Collaborator

mnieper commented Nov 24, 2021

I know that you have added a "fix" to optionals.sld when it is used outside of Chibi, but the fix is not in init-7.scm, which contains the definition of let-optionals* for Chibi if I am not mistaken. Of course, it would be trivial to amend the latter as well.

The fix is not needed in init-7.scm because that is only used by Chibi and the order of evaluation is guaranteed in Chibi. Again - if you think there is an error please provide a failing test case before claiming there is an error.

If you guarantee the order of evaluation for future versions of Chibi as well, everything is fine, yes. But as it is hard to write test cases for checking the order of evaluation (unless we know a prior it is always the same), personally, I'd prefer an explicit let* there, which documents the order. Maybe you have an idea to write test cases that cover evaluation order.

I've pushed support for non-optional optional arguments in let-optionals.

I'll have to think about newly allocating a list for rest arguments. That seems like a mistake in the spec, making opt-lambda inconsistent with lambda for which it is an error to mutate the rest argument.

In what sense it is an error to mutate the rest argument for lambda? You are right in that opt-lambda should not be inconsistent with lambda.

@ashinn
Copy link
Owner

ashinn commented Nov 24, 2021

The order of evaluation isn't guaranteed for future versions and needn't be. The guarantee is that the core let-optionals builtin to Chibi works in Chibi. Please stop talking about this unless you can demonstrate a failing test.

Regarding mutating the rest argument for lambda, I must have been thinking of some other issue. It's very late here, I'm off to bed.

@mnieper
Copy link
Collaborator

mnieper commented Nov 24, 2021

The order of evaluation isn't guaranteed for future versions and needn't be. The guarantee is that the core let-optionals builtin to Chibi works in Chibi. Please stop talking about this unless you can demonstrate a failing test.

One can't test this reliably. If Chibi suddenly changes its behavior by coupling the order of evaluation to, say, the phase of the moon but doesn't update the implementation in init-7.scm as well, whatever test I may have written, it may or may not detect an error depending on when we run it.

Tests are good, but they have their limits. The example with the moon phase is, of course, exaggerated, but you know what I mean.

@ashinn
Copy link
Owner

ashinn commented Nov 24, 2021

There is already a test: https://github.com/ashinn/chibi-scheme/blob/master/lib/chibi/optional-test.sld#L72

It's been there for months. It will always pass. If for whatever reason I happen to change the order of evaluation, I will at the same time change the definition in init-7.scm which is distributed with the core and in general can't be used with a different version of Chibi.

I really have no idea what you're talking about.

@ashinn
Copy link
Owner

ashinn commented Nov 25, 2021

OK, I'm not a fan of encouraging mutation, but I added copying of the rest arguments.

The portable R7RS implementation is just 42 lines:

(define-syntax let-optionals*
  (syntax-rules ()
    ((let-optionals* opt-ls () . body)
     (begin . body))
    ((let-optionals* (op . args) vars . body)
     (let ((tmp (op . args)))
       (let-optionals* tmp vars . body)))
    ((let-optionals* tmp ((var default) . rest) . body)
     (let* ((tmp2 (if (pair? tmp) (cdr tmp) '()))
            (var (if (pair? tmp) (car tmp) default)))
       (let-optionals* tmp2 rest . body)))
    ((let-optionals* tmp tail . body)
     (let ((tail (list-copy tmp))) . body))))

(define-syntax let*-to-let
  (syntax-rules ()
    ((let*-to-let letstar ls (vars ...) ((v . d) . rest) . body)
     (let*-to-let letstar ls (vars ... (v tmp (tmp . d))) rest . body))
    ((let*-to-let letstar ls (vars ...) (v . rest) . body)
     (let*-to-let letstar ls (vars ... (v tmp tmp)) rest . body))
    ((let*-to-let letstar ls ((var tmp bind) ...) rest . body)
     (letstar ls (bind ... . rest)
              (let ((var tmp) ...) . body)))))

(define-syntax let-optionals
  (syntax-rules ()
    ((let-optionals ls (var&default ... . rest) body ...)
     (let*-to-let let-optionals* ls () (var&default ... . rest) body ...))))

(define-syntax opt-lambda
  (syntax-rules ()
    ((opt-lambda vars . body)
     (lambda args (let-optionals args vars . body)))))

(define-syntax opt*-lambda
  (syntax-rules ()
    ((opt*-lambda vars . body)
     (lambda args (let-optionals* args vars . body)))))

(define-syntax define-optionals
  (syntax-rules ()
    ((define-optionals (name . vars) . body)
     (define name (opt-lambda vars . body)))))

(define-syntax define-optionals*
  (syntax-rules ()
    ((define-optionals* (name . vars) . body)
     (define name (opt-lambda* vars . body)))))

@mnieper
Copy link
Collaborator

mnieper commented Nov 25, 2021

OK, I'm not a fan of encouraging mutation, but I added copying of the rest arguments.

Neither am I a fan of encouraging mutation, and mutation of rest arguments, in particular. That it is possible in SRFI 227 is only to maintain equivalence to (opt-)lambda in standard Scheme. In the long term (meaning as part of language evolution), Racket's approach of making the rest argument immutable is probably the best.

The portable R7RS implementation is just 42 lines:

Thanks a lot for offering SRFI 227 in Chibi!

I really have no idea what you're talking about.

My point was that writing a test that reliably signals a failure should the order of evaluation (or the implementation of let) be changed but one forgets at the same to update the let-optionals* code in init-7.scm is hard, isn't it? If the order of evaluation is just changed into a left-to-right order, the test you pointed at, will reliably fail. But what about if the order of evaluation neither becomes left-to-right, nor right-to-left but depending on the context? (Imagine an optimization pass that re-schedules independent instructions in some future hypothetical Chibi version). Unless I am mistaken with the above argument, I thought it is easier to be explicit with the order of evaluation in the source than trying to find a test that will surely detect inconsistencies. (It's just a minor point, anyway, so we don't have to waste too much time with it.)

@ashinn
Copy link
Owner

ashinn commented Nov 26, 2021

Your point now seems to be about general testing best practices, and unrelated to the issue at hand which is about Chibi support for SRFI 227.

Your earlier claim that it didn't support mutation of the input is simply false, and is causing a lengthy discussion. The last time you brought up the same issue it was also false, despite the lengthy discussion that ensued. In both cases, if there were an actual problem a simple test case would have demonstrated it. This is separate from the issue of whether that particular test case would always catch all possible regressions.

Because I'm busy I'm making a simple request, for the second time now - if you find a bug please demonstrate it with a test case before claiming there is a problem.

@mnieper
Copy link
Collaborator

mnieper commented Nov 27, 2021

My first post on this issue was exactly about tests; I asked Daphne to run the examples of SRFI 227 against her Chibi implementation as I knew that at least the bindings with no defaults of let-optionals(*) were a discrepancy.

Later I made a second point about that SRFI 227 supports mutation but Chibi doesn't. The latter claim I derived from Chibi's documentation; my line of thought then was that if the documentation of a library says that mutation is not allowed then regardless of whether the actual implementation allows it one shouldn't rely on it as it may be dropped at any time.

You are right that if I had presented enough test cases at that point, it would have shown that set!ing the first argument would have worked as described by SRFI 227 (and that the original version in Chibi did not copy the list of remaining arguments). I would have probably still pointed out the implementation in init-7.scm because nonetheless, I find it a bit brittle - and here comes the argument about testability. That said; it's your code and the "brittleness" is just my personal, subjective opinion so you have all rights to ignore that.

Anyway, I have understood your point. You'll always receive test cases from now on. 😃

PS I don't want to open the can of the other issue again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants