(It's (define-method (f #:key foo) ...).)

This is a valid point. Certainly there should be unambiguous rules so that we know which method should be selected. (I planned to examine this aspect before applying my patch to Guile. I was just eager to share what I had done in order to collect opinions before putting too much effort into it.)

In this case, I would say that positional *should* win since it is most specific with regards to the specifiers.

The patch I posted actually doesn't result in this, but it could be easily fixed with a change based on the following consideration:

The motivation for having what you call the "major limitation" of not doing type dispatch on keyword arguments in GOOPS or CLOS is to strike a reasonable balance with regards to the complexity of implementation (and cognitive load for the user, I guess :). In the future, if we come up with a conceptually simple picture of how to regard method precedence in the light of typed keyword arguments and also see that this doesn't make the implementation overly complicated, we can consider extending the functionality in this direction.

CLOS has a fixed number of required arguments per generic function.  So, in CLOS it isn't possible to come up with two allowed methods where the order of dispatch is unclear.

We loosed that up in GOOPS and allow varying number of arguments (which is a Good Thing). So, you are right that we need to come up with rules that make the order of dispatch clear.

I propose that the simplest rule which corresponds to restricting type dispatch to non-keyword arguments is to define the specializer list of every method with keyword formals like this:

Method formals: ((<F1> <TYPE1>) ... <KEYWORD> ...)

results in

Specializer list: (<TYPE1> ... . <top>)

So

  (method ((x <integer>) . y) ...)

will have the same specializers as

  (method* ((x <integer>) #:key z) ...)

With this definition, positional above will win. In my patch, this corresponds to changing #''() to #'<top> in the computation of specializers for keyword methods.

Meanwhile, I've found a further bug in my patch: We need to consider keyword arguments in re-definition in methods. Fixed now in my still private code.

Also, I should add that I now lean towards supplying the keyword functionality in additional syntax method* and define-method*, and keep the semantics for method and define-method as is.

Best regards,
Mikael

On Sat, Nov 23, 2024 at 4:49 PM Maxime Devos <maximedevos@telenet.be> wrote:

>Well, these particular examples aren't valid since GOOPS doesn't allow type specifiers for keyword arguments. (It's the same in CLOS.) Type dispatch is done *only* on the required arguments.

 

That’s a shame, it should support them IMO, it’s a major limitation if it doesn’t.

 

A variant with untyped keyword arguments:

 

(define-method (f (a <keyword>) (b <symbol>))

  (pk 'positional))

 

(define-method (f (#:key foo))

  (pk 'optional-keyword foo))

 

(f #:foo 'bar)

 

Who should win? Both are a quite specific match.

 

Best regards,

Maxime Devos