Hi Stéfano,
Am 09.03.2018 um 16:48 schrieb Stefano
Troncaro:
A few thoughts
I think macro definitions for all the define- functions
can be avoided like this:
\version "2.19.80"
\include "oll-core/package.ily"
#(define-macro (with-options func-def-proc vars preds rulings . body)
`(,func-def-proc ,(append '(opts) vars) ,(append '(ly:context-mod?) preds)
(let* ((rules ,rulings)
(props (context-mod->props rules #t opts)))
. ,body)))
testRules =
#(with-options define-void-function () ()
`((ind ,number? 5)
(target ,symbol?)
(payload)
(accepted-arg ,fraction? opt)
(accepted-without-type opt)
(msg ,string? "No message given"))
(pretty-print props))
\testRules \with {
msg = "Something"
unk = "Unknown option"
target = something
% accepted-arg = 7/4
% accepted-without-type = #(ly:make-moment 3/16)
}
Yes, I like this very much. You still have the familiar
define-X-function with the args and predicates in the usual place,
but with 'with-options' you signal that there will be a rule set for
options.
With respect on how to write the rule-set, based on
your input I see a few possibilities:
1) A very slight modification of its current form
`((rule-enforcement strict)
(ind ,number? 5)
(target ,symbol?)
(payload)
(accepted-arg ,fraction? opt)
(accepted-without-type opt)
(msg ,string? "No message given"))
This keeps the "list of lists" approach you wanted.
I'm not 100% sure if I have a strong opinion between this and your
hierarchical suggestion. But I *think* I like this one more.
I agree with you that options with a default value become optional
and should not have to be flagged as such separately.
I think that the parsing of the options could be set to
'flexible' by default and it can be made strict adding that
as the first element of the list. Alternatively, a
rule-enforcement element may be required.
I suggest to require the statement about rule-enforcement because
otherwise one would probably always confuse things.
But *if* we require it - and as the first element - it doesn't have
to be a list (which would BTW rule out an option with that name) but
can be a symbol:
`(strict
(ind ,number? 5)
...
2) Optional arguments could be anticipated with an opt instead
of having it at the end:
`((ind ,number? 5)
(target ,symbol?)
(payload)
(opt accepted-arg ,fraction?)
(opt accepted-without-type)
(msg ,string? "No message given"))
This requires the same input as before but feels clearer to my
eyes.
I partially disagree. Not with the idea of having the flag in front
of the list but with using a/that symbol. Apart from ruling out 'opt
as an option name (OK, in my implementation 'opt couldn't be used as
a *default*) I think this is confusing because you have a first
"column" of payload - opt - msg.
What do you think about
`(strict
(ind ,number? 5)
(target ,symbol?)
(payload)
(? accepted-arg ,fraction?)
(? accepted-without-type)
(msg ,string? "No message given"))
?
Technically it's still a symbol but indicates much better the idea
of "optional".
I see what you mean about the POV defining what can be
called optional. As I described earlier, the "caller" POV
feels more intuitive for me but that may just be personal
taste. Without more opinions it's difficult to tell.
3) The "elimination of unnecessary parens" is indeed a very
minor thing. That approach felt instantly familiar because it
resembles how function predicates are defined, in that only
the proc is written when there is no default value, but the
proc and the default value are parenthesized when they are
needed together. In the same logic, I thought the key could be
by itself when all one needed was to communicate "this is
optional" or "this is required", and parenthesized with more
information when needed.
My previous idea was merely just these three together. As
you pointed out, I think the first is the one of real
importance, and the others are more in the realm of QOL
suggestions.
For now I'll await your thoughts, and I'll open a pull
request later.
I'd be glad about a PR along these lines!
Best
Urs
|