mighty-gerbils / gerbil

Gerbil Scheme
https://cons.io
GNU Lesser General Public License v2.1
1.15k stars 110 forks source link

Interface Method namespaces #1266

Open drewc opened 3 weeks ago

drewc commented 3 weeks ago

The issue is simple: dynamic methods have no namespace and interfaces cast to them. Also, different interfaces (aka typeclasses) could have different methods with the same name. And curly's should {be-not-prefixed 'by-default 'for 'KISS}

In short; module/name#interface-name::method-name for the default allows both easy dispatch AND static signature checking while keeping name and module separation to make unintended duplication difficult.

The solution is a namespace: keyword that acts similar to the externone only defaults to the interface name. If it's #f, no namespace. It could also be prefix:.

So, (interface foo (bar baz)) will, at prototype, look for and bind the foo::bar method. It could then, if foo::bar does not exist, look for the :bar method, and then the bar method. That solves almost all the problems, right?

Then (interface (bat foo) (xyz n)) could first look for the bat::bar method before the foo::bar et al methods. That allows for some interesting specialization while allowing a hierarchy. outside of class/types.

But (interface (fu namespace: foo) (bar me)) could lookup foo::bar as well?

Should the prefix actually be module/name#foo::bar by default? I think that may be better as I can have interfaces with the same name and same functions but in a different space.

So (rename: food foo) on an export and then in another module (interface (foo food) (bar baz)) could have an another/module#foo::bar first dispatch attempt?

Thoughts?

vyzo commented 3 weeks ago

I think this is very important for multiple reasons:

The proper solution is for each interface, we define a method namespace (default: the module namespace + the interface name + the method name, so as drew suggested module#Interface::method. The interface macro will emit a linearized list of method names in the interface descriptor, instead of a single unnamespaced one, and similary the prototype creation will resolve for a particular class in the linearized order. Finally, the defmethod macro will get a interface: directive to do the proper namespacing at the binding site.

This will leave the global namespace reserved for dynamic dispatch methods, which is a big enough namespace. The restriction will be that you need to namespace your defmethods, but I was planning to enforce that anyway for static type checking and safety.

vyzo commented 3 weeks ago

cc @fare