Re: Quick vote about portable keyword argument syntax Lassi Kortela 03 Nov 2019 09:56 UTC
Thanks for sticking with the discussion even though your opinions have been in a minority all this time. I'm confident we can find some way to do keywords that doesn't preclude hygienic identifiers and doesn't mandate parsing magic symbols like :foo and foo:. The 177 macros don't need to be the be-all end-all syntax for using keyword args. >>>> (let ((:e 3)) >>>> (keyword-call foo 1 2 :e 4)) >> >> The `e` keyword argument would get the value 4. >> >> The lexical binding (if any) of the symbol would >> simply be ignored; the symbol would be used for its name only. > > Please, don't let us standardize this behavior (maybe as a hack until > we have proper keywords, but not for inclusion into R7RS-large). In my view, what matters is the semantics (that lambdas can declare keyword arguments, and there is some way to call one and supply them). I also find it important that keyword lambdas can be called like ordinary lambdas (which allows adding keyword arguments to procedures that did not take any before, e.g. the port settings in John's pre-draft). The kw syntax doesn't matter; Scheme can and will have multiple such syntaxes for many years. So if R7RS-large wants to have a completely different syntax to define and call keyword lambdas, that's perfectly fine with me as long as the semantics are compatible with SRFI 177. > This would be just a wart in the Scheme language, destroying Scheme's > uniformity. We call that a macro :) But seriously, you have a good point and I agree. The reason I think it's acceptable in this case, is that several Schemes already treat foo: and/or :foo as a non-identifier. So if you're reading random Scheme code and see :foo or foo: in there, and don't carefully check which implementation it was written for, you cannot assume that it is an identifier. Hence from my point of view, 1777's call/kw would not really be introducing new ambiguity to the language; it would just formalize the old ambiguity. That's not ideal, but I think it's better than the alternatives where you read foo: or :foo inside a call/kw, and it may or may not be a keyword object depending on the implementation. Put yet another way: 8 Scheme implementors as well as DSSSL have already destroyed the uniformity of identifiers; I'm just documenting the job :) > Local bindings shadow every identifier, whether bound to > variables, to macro keywords, pattern variables, or whatever. For > example, even the ellipsis can be shadowed by a local binding (the > following expression is not an error but evaluates to the symbol foo): > > (let ((... 'foo)) > (define-syntax bar (syntax-rules () ((bar) ...))) > (bar)) > > Option 2 would destroy part of Scheme's simplicity through uniformity. I agree. In my view, it's more a question of what is an identifier and what is not. Currently :foo and foo: are indeed read as identifiers in most Scheme implementations, but not in all of them, so their status as an identifier is already unclear. Some implementations even have reader options that change whether those are read in as identifiers on the fly. The call/kw abstraction is leaky, because |:foo| and |foo:| with vertical bars are probably read as identifiers even in all Schemes that have keyword objects; whereas call/kw would read them as keywords. But this is getting into really esoteric corner cases. >>>> So what about the following Option 3? >>>> >>>> (keyword-call foo 1 2 : e 5) >>>> >>>> In Schemes with a keyword reader syntax, it can be expressed as >>>> >>>> (keyword-call foo 1 2 #:e 5) >> >> Do you mean that in the case of more than one keyword argument, the >> colon would be repeated like this: >> >> (keyword-call foo 1 2 : e 5 : f 6 : g 7) > > Both options are possible (so we have an Option 4) if positional and > keyword arguments do not have to be mixed. > >> That's certainly possible, but I imagine it doesn't look very familiar >> to people, and they would keep typing the colon and keyword name >> together (without a space in between) out of habit, since that's what's >> done in many/most Lisps with keywords. > > I don't think we would demand too much from the average Scheme programmer. It's definitely not too much to demand intelligence- or sophistication-wise. But IMHO it reads unnaturally, and it's one of those little things that has to be kept in mind. Good design means people don't need to think about the details; the intuitive way to do things is also the right way. > In the long term, we can hope that "#:key" will be standardized, > creating a new type of Scheme object that does not clash with the > semantics of identifiers. We all agree that would be ideal. 177 just has to do a compatibility hack in the meantime. If R7RS-large gets keyword objects, maybe it can use a version of call/kw that only accepts keyword objects and doesn't try to parse identifiers. I would not be opposed to that. IMHO R7RS-large can have keyword arguments without requiring them to be used with the 177 macros. >> This also doesn't make it obvious what to do about hygienic vs >> non-hygienic keywords. Would : use a hygienic keyword, and :: (two >> colons) a non-hygienic one? Or vice versa. We are stuck with the same >> problems that we have if there is no space after the colon. >> >> I guess one more alternative would be having only one delimiter: >> >> (keyword-call foo 1 2 : e 5 f 6 g 7) >> >> That's very similar to the originally proposed syntax of having the >> keyewords in a list, but IMHO less clear: >> >> (keyword-call foo 1 2 (e 5 f 6 g 7)) >> >>>> Option 3 is also implementable using syntax-rules alone. >> >> That's very nice, but is that true? Is it able to match the ': symbol at >> the start of a list? > > As John wrote, : would exported by SRFI 177 and call/kw would compare > to the binding of :. Nice. For this kind of syntax, I would still prefer (call/kw 1 2 3 (a 4 b 5 c 6)) however. Since this is Lisp, I think it's more obvious to use a list than a delimiter to indicate substructure. Keywords like :foo are an exception because they've been around for decades so we've grown used to them.